OOM和ANR的区别:
OOM是指内存溢出,是由于过多地使用内存导致的;而ANR是指程序无法响应了,一般是由于过多地使用CPU资源(大量的耗时任务)导致的,Android规定,当Activity在5秒之内无法响应屏幕触摸事件或者键盘输入事件就会出现ANR,而BroadcastReceiver如果在10秒之内还没执行完操作也会出现ANR
性能优化
1. 布局优化
思想1:尽量减少布局的层级,层级少了意味着Android绘制时的工作量少了
方式一:选择合适的布局去减少层级,比如说,虽然RelativeLayout比LinearLayout复杂,一对一的比较的话,能使用LinearLayout就使用LinearLayout,但是如果在实现某个布局时,如果使用LinearLayout要使用嵌套,而使用RelativeLayout会用到更少的层级,那么选择使用RelativeLayout
方式二:使用<merge>标签,比如说在使用<include>引进布局时,如果引进布局的根元素和被引入布局的地方的父布局的元素是一样的时候,可以将引进布局的根元素换成<merge>标签代替,这样引进布局后,布局的元素就会被加到指定布局中,从而减少了布局的层级
思想2:布局重用,减少对某个布局的重复创建
使用<include>来引进可重用布局,使用方式:使用layout属性指定布局文件的id。需要注意的是,在为<include>指定id时,如果原布局根元素也有id,则以<include>指定的id为准,而且在使用了任何以layout_开头的属性(在include中只支持这类属性),就必须为layout_width/height赋值
思想3:按需加载,减少没必要的开销
使用<ViewStub>标签来装载需要按需加载的布局,有几个必须要指定的属性:需要指定ViewStub的id;需要用inflatedId属性指定需要加载的布局的id,需要用layout属性指定需要加载的布局文件id,需要指定ViewStub的width/height。在需要加载布局时,如果只要加载而已,可以使用((ViewStub) findViewById(…)).setVisibility(View.VISIBLE)来直接使其显示,而如果是需要在加载布局后进行一些操作的,可以使用View view = ((ViewStub) findViewById(…)).inflate()来加载获得view,然后在对view操作,然后将view附给指定的ViewGroup
2. 绘制优化
绘制优化的思想:避免在onDraw中执行大量的操作,主要体现在2个地方
一是不要在onDraw中创建新的局部对象,因为局部对象在用完后如果没被摧毁,当onDraw方法被频繁调用时,会产生大量的临时对象,这样会占用过多的内存,而如果会被摧毁,系统就会频繁地进行gc,也就是:垃圾回收,也会降低执行效率
二是不要在onDraw中执行耗时的任务,或者是次数较多的循环操作,因为这会导致view的绘制变得不流畅
3. 内存泄漏优化
内存泄漏优化的思想:一是避免写出有内存泄漏的代码,二是通过内存分析工具,比如MAT来找出内存泄漏,然后解决
常见的内存泄漏:
静态变量指向了需要在用完后摧毁的对象(比如说Activity):因为静态变量会一直存在在内存中,当它指向一个对象后,该对象就会一直存在至程序关闭,这就会导致对象不能正常摧毁
单例模式中的变量指向了需要在用完后摧毁的对象(比如说Activity):因为单例模式的生命周期和Application是一样的,如果单例模式的某个变量指向了一个对象,那么这个对象就会一直存在至程序关闭,就会导致对象不能正常摧毁,比如说,用Activity来初始化单例里的Context,或者说传递进继承了某个接口的活动来初始化单例里的接口
属性动画没有及时关闭导致内存泄漏:如果在某个活动中执行无限循环的动画,并且没有在onDestroy的方法关闭动画(关闭方法:Object/ValueAnimator的实例的cancel方法),那么该Acitivity的某个view会一直被这个动画所持有,而这个view又持有Activity,就会导致Activity的销毁异常
4. 响应速度优化
响应速度优化的思想:避免在主线程中做耗时的操作,将耗时操作放在子线程中去执行,也就是使用异步方式执行耗时操作
当发生ANR时,可以使用ANR日记去分析出ANR的原因:当发生ANR时,系统会在/data/anr目录下产生一个traces.txt的文件,使用adb pull /data/anr/traces.txt命令在终端导出traces.txt文件,然后分析这个文件就可以定位ANR了
需要注意的是,并不是把耗时操作放到子线程就不会导致ANR了,比如说一种常见的场景:主线程在初始化时需要子线程的耗时操作执行完后的数据,那么就会导致ANR,或者导致主线程的初始化没有达到预期的效果
5. 线程优化
线程优化的思想:采用线程池
6. Bitmap优化
使用设置option或者矩形的方式,另外介绍
7. ListView优化
采用ViewHolder;根据列表的滑动状态来控制任务的执行频率;使用开启硬件来加速
性能优化细节:
避免创建过多的对象,在能使用引用,或者能直接使用共享对象时尽量避免创建新对象
不要过多的使用枚举类型,因为枚举类型占用的内存空间比整型大
常量使用static final来修饰,尽量使用静态内部类来代替内部类(还可以避免内存泄漏)
在确定了引用的使用生命周期时,使用一些软引用和弱引用来代替强引用
采用内存缓存和磁盘缓存来减少IO操作的耗时
使用性能更好的、Android特有的数据结构,比如SparseArray、ArrayMap来代替HashMap,再比如Pair