1. 写在前面
1.1 性能优化的工具
- Android开发者选项
重点说下Profile GPU Rendering,实时反应当前每一帧的耗时,可用于分析卡顿的地方。 - 分析具体耗时的Trace view以及整体情况的Systrace
Systrace用于对特定时间段内如UI或动画的整体情况,而Trace view用于对性能分析进行说明,可以分析到每一个方法的执行时间,可以统计出该方法的调用次数和递归次数,CUP占用百分比等。 - 布局复杂度工具Hierarchy View
可以查看布局的层级,Measure,Layout和Draw的对应耗时。 - 应用启动时间
// 测试Activity启动时间,如MainActivity,APP启动时间 adb shell am start -W packagename/activity
- 静态代码检查工具Lint
- 程序稳定性monkey
- 使用LeakCanary检测内存泄露
1.2 优化的一些点
1.2.1 布局优化
- 使用FrameLayout等布局,减少嵌套层级,尽量不使用RelativeLayout做根布局,RelativeLayout会让子View调用2次onMeasure,而且布局相对复杂时,onMeasure相对比较复杂,效率比较低,LinearLayout在weight>0时也会让子View调用2次onMeasure。LinearLayout weight测量分配原则。
- 使用include、ViewStub、merge等标签。
- 使用TextView的leftDrawabel/rightDrawable代替ImageView+TextView布局
- 注意使用wrap_content,在测量过程中,match_parent和固定宽高度对应EXACTLY ,而wrap_content对应AT_MOST,这两者对比AT_MOST耗时较多。
- 尽量使用View.GONE取代View.INVISIBLE,或减少使用透明度。
- 自定义View的优化, onDraw中不用new对象,会引起内存抖动。使用 canvas.clipRect()来帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。
- 移除xml非必须的背景、移除window中默认的背景、按需显示位图。
- 减少刷新次数,缩小刷新区域。
1.2.2 加载优化
-
将耗时的操作封装到异步中去,但多进程情况下,Application的onCreate会被执行多次,注意可能会出现的问题。
-
Json反序列化
json反序列化是指将json字符串转变为对象,这里如果数据量比较多,特别是有相当多的string的时候,解析起来不仅耗时,而且还很吃内存。解决的方式是:
a、精简字段,与后台协商,相关接口剔除不必要的字段。保证最小可用原则。b、使用流解析,之前我考虑过json解析优化,在Stack Overflow上搜索到这个。于是了解到Gson.fromJson是可以这样玩的,可以提升25%的解析效率。
public List<Message> readJsonStream(InputStream in) throws IOException{ JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); List<Message> messages = new ArrayList<Message>(); reader.beginArray(); while (reader.hasNext()){ Message message = gson.fromJson(reader, Message.class); messages.add(message); } reader.endArray(); reader.close(); return messages; }
1.2.3 内存优化
- 加载大图时按需加载,合理选择inSampleSize,使用LruCache缓存。
- 使用线程池管理线程。
1.2.4 内存泄露优化
- 资源性对象未关闭释放。如Cursor、File等。
- 注册事件的注销,如广播、事件注册后未注销、观察者列表维持着对象的引用。
- Handler泄露。
private static class MyHandler extends Handler { private final WeakReference<MainActivity> mActivity; // ... public MyHandler(MainActivity activity) { mActivity = new WeakReference<MainActivity>(activity); //... } @Override public void handleMessage(Message msg) { } //... }
- 尽量使用静态内部类。
- 在Callback里打印log。
2. 卡顿优化
2.1 卡顿的场景
卡顿的场景可以从UI(绘制、刷新)、启动速度(冷热启动)、跳转(页面间,前后台)、响应(按键、系统事件、滑动)四个方面去分类,主要原因还是以下两种:
-
界面绘制
绘制的层级深度、页面复杂度、刷新不合理。 -
数据处理·
数据在UI线程处理、数据处理占用CPU过高、内存分配不合理导致频繁GC。
2.2 启动速度
启动速度的话,可以使用adb命令查看启动时间。
// 测试Activity启动时间,如MainActivity,APP启动时间
adb shell am start -W packagename/activity
冷启动黑白屏问题,可以通过设置theme设置background来解决;冷启动与热启动速度问题,需要优化UI线程的处理逻辑。
2.3 稳定性优化
- 采用TDD开发模式,提高单元测试覆盖率,方法的测试覆盖率。
- 使用Android Lint等静态工具,提高程序的稳定性。
- 使用Monkey测试等工具,减少隐藏的闪退。
adb shell monkey -p com.your.packagename -v 10000
- 使用bugly等Crash监控上传工具,便于持续提升程序的稳定性。
3. APK瘦身
1. 开启shrinkResources去除无用资源
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
}
}
}
shrinkResources依赖于minifyEnabled,就是打开shrinkResources也必须打开minifyEnabled。
2. 借助Android Lint删除未使用的资源代码
Analyze -> Run Inspection by Name -> unused resources -> Moudule ‘app’ -> OK
Analyze -> Run Inspection by Name -> unused declaration -> Moudule ‘app’ -> OK
3. 压缩图片或使用webp格式图片
使用pngquant优化png图片的大小
// pngopt.sh
#! /bin/bash
set -eux
find . -name '*.png' -print0 | xargs -0 -P8 -L1 pngquant --ext .png --force 256
4. 使用插件化
插件化可以将APK的体积减小,在用户需要使用到相关模块后,再从服务器进行下载。
5. 向量图优化(去除向量图小数点)
使用\.\d+
去除向量图中的小数点,可以编写一个python脚本全局执行,代码较多,我这里就不展示了。
4. 省电流量优化
- 使用Battery Historian 系统电量分析工具,分析耗电过程,优化APP耗电。
一般耗电的场景有:- 计算优化,减少或避开浮点运算等。
- 避免wakelock的使用不当,屏幕唤醒是耗电最厉害的,特别注意。
- 使用Job Scheduler。
- 使用GPS定位耗电,但定位进准,如果要求不那么进准的话,可以使用wifi/移动网络进行定位。
- 网络差的情况下,减少一些比不要的请求加载,如加载一张大图等,另没有wifi/蓝牙可连的情况下,尽量关闭。
- 流量优化的话,只能说尽量减少不必要的请求了,减少下载,比如使用缓存。
总结:其实一定程度上,严格按照代码规范来执行,很大程度上就能避免很多问题,上面的这些性能优化措施,只能是后面出现问题的解决方案,重要的是我们要去学会编写高质量的代码,从而避免这些问题的出现。
网友评论