【个人复习向】Android学习过程 以及 问题集合
这篇博文记录的是本人的Android学习过程,从Android基础开始,到实际遇到的问题;
橘色表示某一范围内的知识点总结;绿色表示分散的小知识点。
一,Activity 生命周期
Activity是与用户交互的接口,一个activity对应一个窗口。Android系统中是通过Activity栈的方式来管理Activity的,而Activity自身则是通过生命周期的方法来管理的自己的创建与销毁。
1. Activity的四种状态
Active/Running:
Activity处于活动状态,此时Activity处于栈顶,是可见状态,可与用户进行交互。
Paused:
当Activity失去焦点时,或被一个新的非全屏的Activity,或被一个透明的Activity放置在栈顶时,Activity就转化为Paused状态。但我们需要明白,此时Activity只是失去了与用户交互的能力,其所有的状态信息及其成员变量都还存在,只有在系统内存紧张的情况下,才有可能被系统回收掉。
Stopped:
当一个Activity被另一个Activity完全覆盖时(失去焦点并且上层存在不透明的、非Dialog样式的Activity),被覆盖的Activity就会进入Stopped状态,此时它不再可见,但是跟Paused状态一样保持着其所有状态信息及其成员变量,该Activity的数据会在RAM中暂时保留,一旦系统需要内存,这种处于Stopped状态的Activity占用的RAM空间会优先被清理并重新利用。所以,在Activity处于Stopped状态时,必须要保存该Activity的UI状态,否则一旦RAM空间被重新利用,UI状态和数据就完全丢失。
Killed:
当Activity被系统回收掉时,Activity就处于Killed状态。不占用RAM空间。
2. Activity的生命周期
典型的生命周期:创建,运行,停止,销毁
onCreate
创建,它是生命周期第一个调用的方法,我们在创建Activity时一般都需要重写该方法,然后在该方法中做一些初始化的操作。不能在这个阶段写太多耗时的东西。
onStart
运行,此方法被回调时表示Activity正在启动,此时Activity已处于可见状态,只是还没有在前台显示,因此无法与用户进行交互。可以简单理解为Activity已显示而我们无法看见罢了。
onResume
运行,当此方法回调时,则说明Activity已在前台可见,可与用户交互了(处于前面所说的Active/Running形态)。
onPause
此方法被回调时则表示Activity正在停止(Paused形态),一般情况下onStop方法会紧接着被回调。在onPause方法中我们可以做一些数据存储或者动画停止或者资源回收的操作,但是不能太耗时,因为这可能会影响到新的Activity的显示——onPause方法执行完成后,新Activity的onResume方法才会被执行。
onStop
一般在onPause方法执行完成直接执行,表示Activity即将停止或者完全被覆盖(Stopped形态),此时Activity不可见,仅在后台运行。同样地,在onStop方法可以做一些资源释放的操作(不能太耗时)。
onRestart
表示Activity正在重新启动,当Activity由不可见变为可见状态时,该方法被回调。这种情况一般是用户打开了一个新的Activity时,当前的Activity就会被暂停(onPause和onStop被执行了),接着又回到当前Activity页面时,onRestart方法就会被回调。
onDestroy
此时Activity正在被销毁,也是生命周期最后一个执行的方法,一般我们可以在此方法中做一些回收工作和最终的资源释放。
引用及扩展阅读:
https://blog.csdn.net/qq_35559358/article/details/79715222
https://blog.csdn.net/qingxuan521721/article/details/78737080
二,MVP架构 (Presenter)
只知道MVC,MVP是MVC的改良。主要不清楚presenter的作用。
View:主要负责界面的显示及跟数据无关的逻辑,比如设置控件的点击事件等
Presenter:主要负责View与Model的交互
Model:数据部分
任何需要更新或者操作数据的,都间接通过Presenter对象去操作数据
Presenter层持有View层对象的引用,除此之外不持有其他的UI控件等的引用,Model层会把想要更新View的操作委托Presenter去操作,而Presenter层会把更新View操作交给View层对象去操作。
三,了解 RxJava
a library for composing asynchronous and event-based programs using observable sequences for the Java VM
本质是实现异步操作的库,利用了观察者模式。
观察者模式面向的需求是:A 对象(观察者)对 B 对象(被观察者)的某种变化高度敏感,需要在 B 变化的一瞬间做出反应。程序的观察者模式,采用注册(Register)或者称为订阅(Subscribe)的方式,告诉被观察者:我需要你的某某状态,你要在它变化的时候通知我。类似OnClickListener
。
RxJava 的观察者模式有部分不同,有四个基本概念:
Observable (可观察者,即被观察者);Observer (观察者);subscribe (订阅);事件
RxJava的事件回调方法有:
onNext() 普通事件
onCompleted() 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。
onError() 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。
线程切换:基本是依靠ObserveOn和SubscribeOn这两个操作符来完成
引用及扩展阅读:
http://gank.io/post/560e15be2dca930e00da1083#toc_1
四,了解Room数据库
google自己的数据库框架Room。
涉及到的概念:
Entity:具体的bean实体(一个对象类称之为一个javabean,不知道为甚),会与数据库表column进行映射
Dao:数据库访问对象,实现具体的增删改查。
RoomDatabase:提供直接访问底层数据库实现,我们应该从里面拿到具体的Dao,进行数据库操作。
引用及扩展阅读:
https://www.jianshu.com/p/72c8efc3ad87
DAO层操作这个超级全:https://blog.csdn.net/u011897062/article/details/82107709#%E4%BF%A1%E6%81%AF%E6%9F%A5%E8%AF%A2
五,四大组件
Activity:展现为一个可视化的用户界面。这些activity一起工作,共同组成了一个应用程序,但每个activity都是相对独立的。每个activity都 是Activity(android.app.Activity)的子类。展示activity窗体的可视化内容区域是一些具有层次关系(非常像数据结构中的树)的视图,而视图则是由类View的子类表示的。通过调用Activity.setContentView()方法来设置展现activity的窗体的视图。
Service:Android系统的服务(不是一个线程,是主程序的一部分),与Activity不同,它是不能与用户交互的,不能自己启动的,须要调用Context.startService()来启动,执行后台,假设我们退出应用时,Service进程并没有结束,它仍然在后台行。比如,service可能在用户处理其他事情的时候播放背景音乐,或者从网络上获取数据,或者执行一些运算,并把运算结构提供给activity展示给用户。每一个service都扩展自类Serivce。与activity以及其他组件一样,service相同执行在应用程序进程的主线程中。所以它们不能堵塞其他组件或用户界面,通常须要为这些service派生一个线程执行耗时的任务。
Broadcase receiver:用于异步接收广播Intent。
正常广播 Normal broadcasts(用 Context.sendBroadcast()发送) 是全然异步的。没有定义的顺序。
有序广播 Ordered broadcasts(用 Context.sendOrderedBroadcast()发送)每一个receiver执行后能够传播到下一个receiver,也能够全然中止传播--不传播给其它receiver。
专注于接收广播通知信息,并做出相应处理。广播接收器没实用户界面。然而,它们能够启动一个activity来响应它们收到的信息,或者用NotificationManager来通知用户。通知能够用非常多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等等。
Content provider:用于对外共享数据,也就是通过ContentProvider把应用中的数据共享给其它应用訪问,其它应用能够通过ContentProvider对指定应用中的数据进行操作。ContentProvider分为系统的和自己定义的,系统的也就是比如联系人,图片等数据。
以上是四大组件,下面说一下也很重要的intent组件:
intent:一个保存着消息内容的Intent对象。对于activity和服务来说,它指明了请求的操作名称以及作为操作对象的数据的URI和其他一些信息。比方说,它能够承载对一个activity 的请求,让它为用户显示一张图片,或者让用户编辑一些文本。而对于广播接收器而言,Intent对象指明了声明的行为。比方,它能够对全部感兴趣的对象声 明照相button被按下。对于每种组件来说,激活的方法是不同的。此处不赘述,需要阅读,下面有链接~
Application:当android程序启动时系统会创建一个 application对象,用来存储系统的一些信息。通常我们是不需要指定一个Application的,这时系统会自动帮我们创建。
引用与扩展阅读:https://www.cnblogs.com/hrhguanli/p/3961599.html
六,Android 布局
时间有限,我是边上手边学的,所以这部分只记录了我觉得难一点的地方。
Android 圆角、圆形 ImageView 实现
https://blog.csdn.net/jakezhang1990/article/details/79425879
用glide也是很好的选择
如果图片长宽不定,很有可能出现上下两条线或者左右两条线的情况,设置android:scaleType="centerCrop" 很有用,参考如下:
https://www.cnblogs.com/nimorl/p/8081542.html
ConstraintLayout
https://blog.csdn.net/etwge/article/details/80433580
七,View 绘图
1. onMeasure:
作用:
(1)一般情况重写onMeasure()方法作用是为了自定义View尺寸的规则,如果你的自定义View的尺寸是根据父控件行为一致,就不需要重写onMeasure()方法
(2)如果不重写onMeasure方法,那么自定义view的尺寸默认就和父控件一样大小,当然也可以在布局文件里面写死宽高,而重写该方法可以根据自己的需求设置自定义view大小
使用:
onMeasure有两个参数 ( int widthMeasureSpec, int heightMeasureSpec),该参数表示控件可获得的空间以及关于这个空间描述的元数据。widthMeasureSpec和heightMeasureSpec这两个值通常情况下都是由父视图经过计算后传递给子视图的,说明父视图会在一定程度上决定子视图的大小。
specMode一共有三种类型,如下所示:
1. EXACTLY
表示父视图希望子视图的大小应该是由specSize的值来决定的,系统默认会按照这个规则来设置子视图的大小,简单的说(当设置width或height为match_parent时,模式为EXACTLY,因为子view会占据剩余容器的空间,所以它大小是确定的)
2. AT_MOST
表示子视图最多只能是specSize中指定的大小。(当设置为wrap_content时,模式为AT_MOST, 表示子view的大小最多是多少,这样子view会根据这个上限来设置自己的尺寸)
3. UNSPECIFIED
表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。这种情况比较少见,不太会用到。
PorterDuffColorFilter
保持原来图片的形状,而切换图片的颜色
ViewOutlineProvider
实现图像矩形圆角效果
class RoundViewOutlineProvider extends ViewOutlineProvider { private float radius = 100f; private int diameter = 200; public RoundViewOutlineProvider(float radius) { this.radius = radius; this.diameter = (int) radius * 2; } @Override public void getOutline(View view, Outline outline) { int left = (view.getWidth() - diameter) / 2; int top = (view.getHeight() - diameter) / 2; int right = view.getWidth() - left; int bottom = view.getHeight() - top; outline.setRoundRect(left, top, right, bottom, radius); } }
八,Android 动画
https://www.jianshu.com/p/609b6d88798d
Android 中的动画可以分为以下几类: 逐帧动画 补间动画 属性动画。
1. 逐帧动画的原理就是让一系列的静态图片依次播放,利用人眼“视觉暂留”的原理,实现动画。逐帧动画通常是采用 XML 资源进行定义的,需要在 <animation-list .../> 标签下使用 <item .../> 子元素标签定义动画的全部帧,并指定各帧的持续时间。
2. 补间动画就是指开发者指定动画的开始、动画的结束的"关键帧",而动画变化的"中间帧"由系统计算,并补齐。补间动画有四种:淡入淡出: alpha,位移:translate, 缩放:scale,旋转: rotate
3. 属性动画可以看作是增强版的补间动画,与补间动画的不同之处体现在:
属性动画可以看作是增强版的补间动画,与补间动画的不同之处体现在:补间动画只能定义两个关键帧在透明、旋转、位移和倾斜这四个属性的变换,但是属性动画可以定义任何属性的变化。补间动画只能对 UI 组件执行动画,但属性动画可以对任何对象执行动画。
与补间动画类似的是,属性动画也需要定义几个方面的属性:
- 动画持续时间。默认为 300ms,可以通过 android:duration 属性指定。
- 动画插值方式。通过 android:interploator 指定。
- 动画重复次数。通过 android:repeatCount 指定。
- 重复行为。通过 android:repeatMode 指定。
- 动画集。在属性资源文件中通过 <set .../> 来组合。
- 帧刷新率。指定多长时间播放一帧。默认为 10 ms。
主要学习属性动画:
参考引用:https://github.com/OCNYang/Android-Animation-Set/tree/master/property-animation
属性动画实现原理就是修改控件的属性值实现的动画。
类:我们平时使用属性动画的重点就在于 AnimatorSet、ObjectAnimator、TimeAnimator、ValueAnimator。
属性:Android 属性动画提供了以下属性:
- Duration:动画的持续时间;
- TimeInterpolation:定义动画变化速率的接口,所有插值器都必须实现此接口,如线性、非线性插值器;
- TypeEvaluator:用于定义属性值计算方式的接口,有 int、float、color 类型,根据属性的起始、结束值和插值一起计算出当前时间的属性值;
- Animation sets:动画集合,即可以同时对一个对象应用多个动画,这些动画可以同时播放也可以对不同动画设置不同的延迟;
- Frame refreash delay:多少时间刷新一次,即每隔多少时间计算一次属性值,默认为 10ms,最终刷新时间还受系统进程调度与硬件的影响;
- Repeat Country and behavoir:重复次数与方式,如播放3次、5次、无限循环,可以让此动画一直重复,或播放完时向反向播放;
贝塞尔曲线:
1、moveTo:不会进行绘制,只用于移动移动画笔。
2、quadTo :用于绘制圆滑曲线,即贝塞尔曲线。
mPath.quadTo(x1, y1, x2, y2) (x1,y1) 为控制点,(x2,y2)为结束点。同样地,我们还是得需要moveTo来协助控制。
mPath.moveTo(100, 500); mPath.quadTo(300, 100, 600, 500); canvas.drawPath(mPath, mPaint);
效果如图:
3、cubicTo:同样是用来实现贝塞尔曲线的。
mPath.cubicTo(x1, y1, x2, y2, x3, y3) (x1,y1) 为控制点,(x2,y2)为控制点,(x3,y3) 为结束点。多了一个控制点而已。
mPath.moveTo(100, 500);
mPath.cubicTo(100, 500, 300, 100, 600, 500);
结果和上图一样。
如果我们不加 moveTo 呢?则以(0,0)为起点,(100,500)和(300,100)为控制点绘制贝塞尔曲线:
Android Animation运行原理
https://www.jianshu.com/p/fcd9c7e9937e
想要做更酷炫的效果,一般就需要涉及Animation的原理,Android使用一个3*3的矩阵处理平移、缩放、旋转等动画效果,假如我们想要实现一个平移(a,b)之后旋转(c,d)的动画,那用Matrix的实现代码就是这样的:
Matrix matrix = new Matrix(); matrix.setTranslate(a, b); matrix.postScale(c, d);
Animation的applyTransformation()方法是空实现,具体实现它的是Animation的四个子类,而该方法正是真正的处理动画变化的过程。applyTransformation()方法就是动画具体的实现,系统会以一个比较高的频率来调用这个方法,一般情况下60FPS,是一个非常流畅的画面了,也就是16ms。我们可以覆写这个方法,快速的制作自己的动画。
https://www.cnblogs.com/kross/p/4087780.html
Android运行时的动画卡顿问题:
我的项目中,页面不仅在播放动画,还在播放gif(承载动画的view本身是一个gif),以及还在播放视频,效果是有很明显的卡顿和gif掉帧的。
问题出在内存泄漏,主线程任务过多,以及启用GC频繁。
我查了资料过后,使用了以下硬件加速,结果是没效果。
经过查看GC启用频率,确实启用的非常频繁,想要减少GC,就要尽可能少的创建临时变量,由于我使用的是属性动画,创建一个AnimatorSet和多个ObjectAnimation,确实很多,可以尝试这样改改,看有没有效果:
可以按照下面这个博文的思路改代码:
https://blog.csdn.net/rentee/article/details/52251829
====================改完代码的分割线==========================
优化过后,发现内存占用不仅没少反多了,emmmmm(没有多很多)
反思了一下,我个人浅薄认为,虽然减少了很多ObjectAnimation对象的创建,但是产生了许多PropertyValuesHolder 对象 以及 Keyframe 对象,而且我的动效比较复杂,经常穿插多个view的动画,最终它们需要在一个set里面,那么还是不可避免的需要创建ObjectAnimation。 所以改完代码过后,临时变量反而更多了,这些是我的猜测,但是确实在我的实验中,这么写不起优化作用。
这时候看到了另一个帖子:
https://blog.csdn.net/qiujuer/article/details/42531485
九,反射
https://blog.csdn.net/lwl20140904/article/details/80163880
为什么用:
1. private类
2. 需要拿到系统级的类
获取Class对象的三种方式
1 Object ——> getClass();
2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
3 通过Class类的静态方法:forName(String className)(常用)
常用第三种方法
譬如说做SDK的时候,想要引用某个包的时候,可以用这种方式,找得到就用,找不到就不用。
GSON内部也是用反射找到输出类型的类,并返回对象。
单例实现的效果是用来做内存级别的操作,实现缓存
缓存
内存缓存 红位数 loser cache
内存缓存的意义是更快的用数据,可以用各种算法。
十,WebView
WebView是android中一个非常重要的控件,它的作用是用来展示一个web页面。它使用的内核是webkit
引擎,4.4版本之后,直接使用Chrome作为内置网页浏览器。
https://www.jianshu.com/p/3e0136c9e748
原子操作
"原子操作(atomic operation)是不需要synchronized"
原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。
如果把一个事务可看作是一个程序,它要么完整的被执行,要么完全不执行(回滚)。这种特性就叫原子性。
常用的XML解析方法
sax:基于事件驱动,逐条解析,适用于只处理xml数据,不易编码,而且很难同时访问同一个文档中的多处不同数据
dom:Dom解析是将xml文件全部载入到内存,组装成一颗dom树,然后通过节点以及节点之间的关系来解析xml文件,与平台无关,java提供的一种基础的解析XML文件的API,理解较简单,但是由于整个文档都需要载入内存,不适用于文档较大时。
JDOM:简化与XML的交互并且比使用DOM实现更快,仅使用具体类而不使用接口因此简化了API,并且易于使用
DOM4j:JDOM的一种智能分支,功能较强大,建议熟练使用
内部类和静态内部类
内部类会持有外部类的对象,打印构造函数是可以看到的,JVM在编译阶段会加进去。
1. 对象创建的方式不同
静态内部类创建对象的时候,独立于外部类及其对象,就好像它是一个独立的类,可以和外部类一样使用。
内部类创建对象的时候,不能独立于外部类,必须要先创建外部类的对象,然后再用这个对象来new出内部类的对象。
2. 内部类不可以有非常量的静态成员
原因很简单,静态成员可以不依赖于对象使用,如果内部类有静态成员的话,就相当于外部类对象直接调用内部类的静态成员,一个是对象,一个是类,不伦不类的。
所以,要给内部类的定义静态成员,必须要使用静态内部类。
非静态内部类是在外部类对象产生的时候才会初始化,所以在没有产生对象时,内部类本身还没有被初始化,这个时候声明一个静态成员,静态成员必须在类加载的时候被加载,所以不能被声明。
匿名内部类
https://blog.csdn.net/hellocsz/article/details/81974251
Listener就是用了匿名内部类。
如果想要在之后remove匿名内部类里面的东西,就不要这么写了,拿不到句柄无法remove。
接口和抽象方法
https://blog.csdn.net/frankfan123/article/details/79628034
设计模式——模板方法模式
https://www.cnblogs.com/chenpi/p/5217430.html
baseActivity 就是用到了这个。
setContentView 作用与用法
作用:给当前activity设置一个layout布局
安卓里的用户界面放在res.layout下,为xml文件,系统自动生成R类,R.layout自动获取res.layout文件夹中的xml文件,再用该语句调用。之后就可以看到页面啦。
setContentView(R.layout.main);
findViewById 作用与用法
作用:获取layout中的某个组件,以便于操作该组件,常见于view,button。
findViewById(R.id.xml文件中对应的idName)
Map<Integer, String> 和 set<Integer>
set集合:元素不允许重复,无序,允许null但最多有一个。
HashMap:无序(Tree有序),遍历Map过程中,不能用map.put和map.remove,会引发 并发修改异常,可以通过迭代器的remove(),从迭代器指向的 collection 中移除当前迭代元素来达到删除访问中的元素的目的。
Map不能用=赋值,用map.put(key,newVal)
// map初始化,以及set初始化和赋值 Map<Integer, String> map = new HashMap<>();
map.put(1, "hihihihihihi"); Set<Integer> set = map.keySet(); //获取map全部key
Java 遍历Map时 删除元素:https://www.cnblogs.com/wxmdevelop/p/5549548.html
final 的用法
final如果修饰类,该类不能被继承;
final如果修饰变量,该变量不能被修改,不能再重新赋值,即变为常量;
final如果修饰方法,该方法不能被重写;
只有被final修饰的局部变量可以用在内联方法里。
使用final的目的大概有以下两条:
1、Java中内部类调用外部类局部变量时要final。
2、当我们写的代码行已经很多的时候,自己可能就忘了之前的意图,把button改了,结果就是:没有按照我们的意愿运行,然后报错。而final修饰后,是不允许修改的,就避免了这样的错误。
引用:
https://www.jianshu.com/p/fd7ce9e3eecb
GSON
GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。可以将一个Json字符转成一个Java对象,或者将一个Java转化为Json字符串。
Handler的作用与用法
Handler是Android SDK来处理异步消息的核心类。子线程与主线程通过Handler来进行通信。子线程可以通过Handler来通知主线程进行UI更新。
个推,以及什么透传消息
文档里面有一句写了:消息推送以个推的透传消息实现。不知道这个透传是什么
透传,即透明传输(pass-through),指的是在通讯中不管传输的业务内容如何,只负责将传输的内容由源地址传输到目的地址,而不对业务数据内容做任何改变。
百科的意思大概就是东西是什么就传什么,那为什么要这样做呢?
透传消息,就是消息体格式及内容,对于传递的通道来说是不去过问的,通道只负责消息的传递,对消息不做任何处理,当客户端接收到透传消息后,由客户端自己来决定如何处理消息。正是因为透传消息可以自定义消息体,也可以自定义消息的展示方式及后续动作处理,所以弥补了通知栏消息的一些不足之处(通知栏消息是直接展示出来,相关的动作客户端无法捕获到)。
透传消息是必须打开应用才能收到,通知是杀死应用也能收到。
看完还是有点不懂,以及如何实现呢
引用和扩展阅读:https://blog.csdn.net/u011136197/article/details/78921988
pollFirst
java.util.LinkedList.pollFirst() 方法检索并移除此列表的第一个元素,或者如果此列表为空,则返回null。
LinkedList
LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList<X> x= new LinkedList<>();
LinkedList.clear() 用于从链接列表中删除所有元素。使用clear()方法只会清除列表中的所有元素,而不会删除列表。换句话说,我们可以说clear()方法仅用于清空现有的LinkedList。
扩展阅读:https://www.cnblogs.com/skywang12345/p/3308807.html
adb pull does not exist
一定要记得先adb remount一下,不然没有读写权限,就找不到设备报does not exist的错误😭
实现list分成20个为一组
int userNum = list().size(); // for ( int i = 0; i<=userNum/20; i++ ){ List<String> whiteList = new ArrayList<>(); for (int j = 0;j<20;j++){ whiteList.add(list().get(i*20+j)); if ( list().size() == i*20+j+1 ) break; } //功能代码区 }
java.lang.ExceptionInInitializerError
抓下来,提示java.lang.ExceptionInInitializerError,于是去找解决办法。
extends
在Java中,通过关键字extends继承一个已有的类,被继承的类称为父类(超类,基类),新的类称为子类(派生类)。
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo
java.lang.ClassNotFoundException: Didn't find class "***" on path: DexPathList[[zip file
出现这个bug的原因有很多,百度一下你可以看到;我试过了网上能找到的所有方法都不行……找了前辈帮忙才解决,说一说我这里报错的原因:类名的命名规范采用大驼峰命名法,一定要严格遵守!我一开始全部小写,改成开头大写就可了。
关于命名规范扩展阅读:https://blog.csdn.net/wenzhi20102321/article/details/61650405
给Thread传递参数
https://www.cnblogs.com/larrylawrence/p/3517897.html
这个文给了我很好的想法,用另外一个有参函数setTar()传递参数。或者可以用回调
延迟执行
如果可以用handler delay写,尽量不要起线程写Thread.sleep。
a method on a null object reference
某方法在一个空指针引用里,有两种情况:1. 实例对象没有实例化 2. 调用的方法返回了NULL给实例,然后实例又去做操作。我检查后发现确实是实例对象没有实例化。
资源复用
新建对象会占用cpu,对象的保留会占用内存,销毁也会占用资源,特别是画图这类的动作。所以尽量减少动作发生,一个解决办法是建立回收机制/等待区,把不用的对象放在等待区,用的时候再引用它们。下面举个栗子:
Android自定义属性时TypedArray的使用方法
https://blog.csdn.net/qq_36523667/article/details/79289821
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
不能在子线程中更新ui
RxJava轮询器:interval
https://www.jianshu.com/p/03958daf4b82
getInstance()
https://www.cnblogs.com/roadone/p/7977544.html 使用getInstance()方法的原因及作用
总的来说:这是单例模式,一般用于比较大,复杂的对象,只初始化一次,应该还有一个private的构造函数,使得不能用new来实例化对象,只能调用getInstance方法来得到对象,而getInstance保证了每次调用都返回相同的对象。
getInstance往往是static的。
Android实现两个循环动画之间互相中断执行,clearAnimation()会导致的bug
中断动画用的clearAnimation(),如果此时动画已经开始执行了,就不能阻止它完成,并且会执行onAnimationEnd;如果在这个阶段,再一次执行这个动画,并且作用在同一个view上,会导致之前clear掉的动画又出现,并且此时两个动画在一个view上,互相牵制,这就是这个错误的表现,跟踪会发现是这个view上有两个动画。
这种情况会出现我们想要在两个动画之间相互切换,A动画在循环的过程中被中断,执行B动画,而A动画并不会立刻中断,还是会去执行onAnimationEnd,而在这个阶段B动画被中断,执行A动画,之前那个动画也会被执行。
Warning: Static member accessed via instance reference
Warning:
Static member accessed via instance reference 通过引用实例来访问静态成员
Shows references to static methods and fields via class instance rather than a class itself. 通过类的实例来显示静态方法和变量的引用,而不是通过类本身
现有一个类Test,有静态方法methods和静态属性fields。
对于静态变量或方法,推荐使用的方式是Test.fields,而不是new Test().fields。
当然,使用this.fields也是不行的!因为this也指向一个实例对象。
如果出现以上告警,那一定是对于java不推荐的方式使用了静态元素。
504错误
504错误是(网关超时) (Gateway timeout) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
这个问题完全是由后端电脑之间 IP 通讯缓慢而产生。
Shallow Size、Retained Size、Heap Size 和 Allocated
https://blog.csdn.net/strange_monkey/article/details/81746232
Shallow size就是对象本身占用内存的大小,不包含其引用的对象。
Retained Size 就是该对象被 Gc 之后所能回收内存的总和。
Retained Size = 对象本身的Shallow Size + 对象能直接或间接访问到的对象的Shallow Size
Heap Size:堆的大小,当资源增加,当前堆的空间不够时,系统会增加堆的大小,若超过上限(如64M,阈值视平台而定)则会被杀掉 。
Allocated:堆中已分配的大小,即 App 应用实际占用的内存大小,资源回收后,此项数据会变小。
建议:若单一操作反复进行,堆大小一直增加,则有内存泄露的隐患,可采用MAT进一步查看。
session
public key 发送给服务端,服务端再生成一个···
请求框架:
retrofit+okhttp
下载:downloadManager 支持断点续传……
getSimpleName名字会比getName更短。
Java反射机制:反射到名字变化多的地方,被混淆的东西,就会报错,要注意。
模块化的时候会用到;调用SDK的时候;调用第三方库;调用系统 …… 的 private成员
注解
混淆
model.bin
部署模型https://www.jianshu.com/p/43da2553a2fb
播放器部分:
mediaplayer:
mediaplayer采用recycleview,有复用机制。但是传入新数据的时候,就会new新的,但是之前的view
还可以用exoplayer
final 和effectively final
针对于jdk1.8,对于一个变量,如果没有给它加final修饰,而且没有对它的二次赋值,那么这个变量就是effectively final(有效的不会变的),如果加了final那肯定是不会变了哈。就是这个意思。
在使用内部类的时候,一个外部变量不能直接被用,但如果它是final或者effectively final就可以被内部类使用了。