Android中的性能优化,对于每一个Android开发者是尤为重要的,做好一个APP不光是功能完善,更要使APP的性能有所提升,才能使APP稳定长久的运行与发展。同时性能优化也是Android面试中最为常见的问题之一,是面试者必须掌握的知识点。
本文将性能优化知识分类论述,主要偏向于优化的场景与解决的方法概述。
分类:
性能优化可分为:
1:卡顿优化——界面要流畅
2:稳定性优化——程序崩溃率要小
3:内存优化——不能有内存泄漏和内存溢出
一:卡顿优化
1:布局优化:
卡顿有一个很大的原因来自于UI,UI的布局优化能够提升程序的流畅度。主要是由于:当布局嵌套多层时,在加载布局时会很耗时,同时在计算布局的各个属性数据时也会耗时从而使程序不流畅造成卡顿。
具体做法:
(1):减少不必要的background和嵌套(可利用开发者选项检测)
(2):合理选用各种view、组件,如RelativeLayout与LinearLayout的选择
(3):巧妙利用
(4):去除不必要的属性(在保证功能的情况下尽量少)
对于具体的开发者选项布局检测、各种布局优化详细做法,可参见我的另一篇文章:
Android布局、渲染优化——学习总结
2:耗时任务处理:
造成卡顿原因
(1):将耗时任务放在UI主线程中执行
(2):未利用线程池,每个任务固定开启一个线程,执行完毕后频繁调用GC机制回收线程
(3):子线程占用CPU率高,导致主线程无法获取CPU时间片执行UI显示任务
解决方法:
(1):避免在主线程中执行耗时任务,如数据处理
(2):不要在broadcastReciever的onRecieve()方法中干活
(3):尽量避免主线程的被锁的情况
(4):多利用线程池进行线程复用和管理
二:稳定性优化
主要指ANR
造成ANR的原因(与上类似):
(1):主线程在做一些耗时的工作
(2):主线程被其他线程锁
(3):cpu被其他进程占用,该进程没被分配到足够的cpu资源
(4):主线程在执行Service的各个生命周期函数时20秒内没有执行完毕
(5):内存溢出
解决方法:
(1):避免在主线程中执行耗时任务,如数据处理
(2):不要在broadcastReciever的onRecieve()方法中干活
(3):尽量避免主线程的被锁的情况
(4):多利用线程池进行线程复用和管理
(5):合理使用 Handler和Asynctask 来处理其他线程请求与异步操作
(6):避免在 onCreate() and onResume() 做过多的事情。
(7):避免内存泄漏导致的内存不足的情况(利用内存检测工具和相应的措施)
同时,对于稳定性来说,程序崩溃率也是稳定性的一个衡量指标。
Android中程序崩溃最常见的一个原因是异常,异常未处理的情况下可能会导致各种情况的ANR,比如最常见的空指针异常、数组下标越界异常、JSON转换异常、classNotFind异常、日期Date转换异常等等。在这些异常发生的时候或者可能发生的时候,注意一定要抛出,同时最好是修改代码防止这些异常的发生。
三:内存优化
1:内存泄漏与内存溢出
内存问题主要是内存泄漏与内存溢出,两者的关系用一句话概括就是:
内存泄漏最终会导致内存溢出(马克思主义中的量变引起质变)。
所以其主要的还是要防止内存泄漏的发生,内存泄漏在很多时候是无法肉眼观测到的,是没有可视化的,这时就需要android的一些内存检测工具,比如Android自带的Android Profiler以及第三方工具LeakCanary。
这里主要介绍一下Android Profiler工具,首先可以点击主页面左上角的View——>Tool Windows——>Profiler,将视图打开,然后连接设备真机,运行程序,之后会看到这样一个页面,如下图所示:
可以看到图中不仅有对内存Memory的检测,还有对手机CPU、NETWORK、ENERGY等的检测。点击Memory,就可以看到整个内存的情况,进入你想检测的某一个页面Activity或Fragment,你可以多次打开,多次退出与清空,然后查看各种引用是否一直存在,若一直存在某些引用,则应该是产生了内存泄漏,需要对这些引用做一些处理,及时释放掉。
2:内存泄漏常见场景
场景一:单例中造成的内存泄漏
单例模式中:由于单例模式的静态特性,单例对象可拥有与应用程序一样长的生命周期,这时若某一对象不再被使用,但该对象的引用仍然被单例对象所持有,就会造成GC无法回收,造成内存泄漏。
解决办法:将传入的context(不管是activity的还是Application的)改为Application的context,使得到的context与应用程序具有一样长的生命周期,这样就算传入的是activity的context,当activity被摧毁时,由于单例对象得到的是application的context,所以不会造成内存泄漏。
场景二:线程造成的内存泄漏
当在非静态内部类中声明并开启一个线程并执行任务时,若这时将activity销毁,则由于任务未执行完毕,无法回收资源,造成内存泄漏。
解决方法:将内部类声明为静态,并且让对象做弱引用,这样就能在活动销毁时就能回收相应资源,同时需要在activity的onDestroy方法中取消任务。
场景三:资源未关闭造成的内存泄漏
在使用完BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源时,一定要在Activity中的OnDestry中及时的关闭、注销或者释放内存。
还有其他的一些场景,见下面链接。
具体内存泄漏相关知识与解决方法,可参考 Android性能优化之内存泄漏处理(图文),写的比较详细,对于面试也有很大的帮助。