花门楼前见秋草,岂能贫贱相看老。这篇文章主要讲述Android应用优化小手册相关的知识,希望能为你提供帮助。
对我们技术从业者而言,很多时候时候不是我们不知道怎么做,而是不知道做什么?今天系统的总结自己关于如何对android应用进行优化的一些经验,共计八个维度.
文章图片
1.布局优化 为什么? Android系统每个16ms发出VSYNC信号,触发对UI的渲染,要想达到界面流畅,必须实现60fps,也就意味着大多数的操作必须在16ms完成.
【Android应用优化小手册】除了上面界面过于复杂导致渲染不能及时完成之外,还存在过度绘制问题.所谓过度绘制就是某个像素在同一帧的时间内被绘制多次.在多层次的UI界面中,如果不可见的UI也在进行绘制,那么这些重合区域的像素就会被绘制多次,从而浪费大量的CPU和GPU资源.过度绘制也发生在背景重叠的情况下,比如Layout中有自己的背景,同时子View中又有自己的背景.
如何检测?
- 使用HierarchyViewer来查找Activity中的布局是否过于复杂
- 在开发者选项中打开Show GPU Overdraw选项进行观察是否存在过度绘制
- 在开发者选项中选择Profile GPU Rendering,选中On screen as bar
- 使用TraceView来观察CPU执行情况
- 减少布局的层级,合理的使用include,merge,ViewStub
- 自定义组件的onDraw()中避免大量创建临时对象,比如String,以免频繁触发GC
- 自定义组件的onDraw()中,考虑使用canvas.clipRect()绘制需要被绘制的区域
- 对像ListView这样的组件容器,考虑使用convertView,使用ViewHolder,
- 考虑使用性能更高的组件,比如推荐使用RecycleView来代替ListView,使用staticlayout来实现自动换行
如何检测?
- 使用LeakCanary
- 使用MAT分析java堆
- 使用Android Device Monitor中的Application Tracker追踪内存分配信息
- Android Studio中的Android Monitor,选择其中的Memory
- 主动的释放内存,在onLowMemory()和onTrimMemory()中适当的释放内存
- 避免内存泄漏和内存溢出
- 在使用Bitmap的时候,考虑对其进行压缩,使用缓存或者改变颜色模式,比如android默认的颜色格式是ARGB_8888,在要求不高的情况下可以采用RGB__565,这样每个像素1占用的内存就可懂4byte到2byte.
- 减少帧动画的使用,如果需要,通过SurfaceView实现
- 使用更轻量级的数据结构,比如ArrayMap/SparseArray
- 合理的使用相关组件,比如Service和Webview,在不需要的时候主动结束其生命周期
- 合理的使用多进程,比如像音乐播放器类,可以分为主进程和播放进程
- 使用异步队列时考虑有界队列
- 如果你能明确知道HashMap的大小,那就再初始化时为其制定容量
?
如何检测?
- 手机选项中通过查看APP的电量消耗的统计数据
- 使用Battery Historian Tool来查看详细的电量消耗
- 减少唤醒屏幕的次数与持续的时间,正确的使用WakeLock.
- 延迟非必须的操作到充电状态时,比如日志上报完全可以在夜间充电时完成,这点可以结合JobScheduler使用
- 使用传感器采集数据时,一旦不需要记得取消注册.
- 减少网络通信,合并通信.
- 合理使用定位功能,减少位置更新频率以及根据实际情况使用不同精度的定位需求
如何检测?
- 使用Android Studio里的Network Traffic Tools来查看网络请求
- 使用Android Studio中的Monitor
- 使用Fidder或者Charles等抓包工具分析网络数据包
- 有必要的时候务必做好缓存,无论是图片还是普通的数据,使用LruCache和DiskLruCache构建自己的缓存系统,并根据实际场景设计缓存策略
- 避免过度的网络同步,合并相关的网络请求
- 根据实际场景确定请求策略,避免使用固定的间隔频率来进行网络操作.比如连接WiFi并充电的情况下请求频率可以高,第一次网络请求失败后可以使用双倍的时间间隔来进行下一次
- 减少数据传输量,对传输的数据做压缩.如果传输的是图片,需要选择合适的图片格式以及根据显示大小请求合适规格的图片.对于普通数据,可以考虑使用ProtocalBuffers来减小传输数据的大小.
- 某些情况下可以采用IP直连,一方面可以减少DNS解析时间,另一方面可以防止域名劫持
如何检测?
- 使用Method Tracing
- 使用Systrace,比如在onCreate中添加trace.beginSection()和trace.endSection()
- 使用
adb shell am start -W [packageName]/[packageName.MainActivity]
测量冷启动时间
- Activity的onCreate()中减少复杂和耗时的操作
- Application的onCreate(),attachBaseContext()中同样减少复杂和耗时的操作,但是对于很多App在此处会执行大量组件和服务的初始化操作,如果可能考虑并行初始化
- 提供自定义启动窗口,比如将一张图片通过设置主题的方式显示为启动窗口.
- 优化布局
如何检测?
- 使用Android Lint检查没有使用的资源
- 减少不必要的依赖库/Jar,在满足需求的前提下优先选择体积小的.
- 使用Proguard工具进行代码瘦身,优化,混淆
- 减少so文件的数量,根据实际情况提供so文件
- 使用Gradle中的shrinkResource来将无用的代码和资源排除在APK安装包之外
- 减少图片资源的大小,考虑图片压缩或者使用Vertor Drawable替代png/jpeg
- 有选择的提供对应分辨率的图片资源
- 复用已经存在的图片,多用通过代码对已有图片进行变换的方式实现复用
- 使用插件化技术(如果项目简单就不要使用)
如何检测?
- 使用Lint执行静态分析,在Android Studio的Analysis-> Inspect Code
- 在开发者选项中开启StrictMode或者在代码中开启
- 代码Review
- 任务并行化,对可能的任务进行并行操作,多借助线程池而非直接使用线程
- 如何需要序列化数据,优先考虑Android自身提供的而非Java提供的Serializable
- 选择合适的数据结构,明确List/Set/Map/Stack操作的复杂度
- 使用Android提供更高效的容器,比如使用ArrayMap来代替HashMap,此外还是有SparseBoolMap,SparseIntMap,SparseLongMap
- 使用静态常量代替Enum类型,可以减少至少两倍的内存消耗
- 使用对象池技术,比如提供想String一样的对象池
- 使用缓存技术
- 字符串拼接操作有限使用StringBuilder
- 对相关的算法和逻辑进行优化,减少不必要的流程
- 采用JNI,对计算量较大的逻辑将其协程so文件,如图片处理
由于每个产品的业务并不相同,也就很难有通用的优化方案,这里又两个目标值得思考:
- 如果有可能,串行业务并行化
- 如果有可能,简化业务流程.将一大象关进冰箱的方法就是打开冰箱,将大象放进去,最后关闭冰箱.
- Android中图片有四种颜色格式,分别是
文章图片
默认的是ARGB_8888
,其中ARGB分别代表的是透明度,红色,绿色,蓝色,每个值分别用8位来记录,也就是一个像素会占用4byte,共32位.
而ARGB_4444
和以上很类似,但是每个值分别用4位来记录,也就是一个像素会占用2byte,共16位.
RGB_565
则分别用5位,6位,5位来记录每个值,不存在透明度,每个像素会占用2byte,共16位.
ALPHA_8
:该像素只保存透明度,会占用1byte,共8位.
在实际应用中而言,值推荐使用ARGB_8888
以及RGB_565
,如果你不需要透明度,那么就选择RGB_565
,可以减少一半的内存占用. ?
推荐阅读
- Android 蓝牙通信——AndroidBluetoothManager
- Android之修改用户头像并上传服务器(实现手机拍照和SD卡选择上传)
- Android文件操作报open failed: EBUSY (Device or resource busy)
- Android 解决手机unauthorized错误
- Android开发必备(命名规范)
- android调试工具adb命令大全
- Android(组件大全)
- Android学习笔记---自定义TextView实现阴影效果
- Android6.0 Home定制