Android性能优化篇
性能优化前言:
性能优化是一个APP不可或缺并需不断重复的工作,性能优化的深度是一个优秀APP的重要凭证,它既繁杂繁琐但也有一定的规则规律。本篇结合实际项目来简单分享一下一个线上产品的优化过程。也非常非常非常期待大家留言交流,指错,分享各自的优化经验~我会收集补充更新收录到本篇。
1、布局渲染 方向:
造成问题:大部分Android显示屏幕是以每秒60帧来刷新的,1000毫秒/60≈16毫秒,所以16毫秒没有完成绘制用户就会感受到卡顿现象出现,绘制布局渲染不得当是卡顿的主要原因,主要是过度绘制(overdraw)布局的层级太深、页面过于复杂等。(动画、频繁的发GC导致堵塞渲染、UI线程中有轻微的耗时操作等因素也会导致卡顿后面详说。)
实用工具:
开发者模式下打开 调试GPU过度绘制 和 GPU呈现模式分析
硬件:调试GPU过度绘制
原色:没有过度绘制;
蓝色:1 次;
绿色:2次 ;
粉色:3 次;
红色:4次以上 ;
监控:GPU呈现模式分析
绿线线:代表16ms 保持动画流畅的关键就在于让这些垂直的柱状条尽可能地保持在绿线下面,任何时候超过绿线,你就有可能丢失一帧的内容,
蓝色线:表示测量绘制时间,很高可能是因为一堆图突然无效(需要重新绘制)或者师徒onDraw函数过于复杂。
红色线:表示执行时间,过高说明复杂的自定义view过多。
橙色线:表示处理时间,CPU告诉GPU渲染一帧的地方。 这是一个阻塞调用,因为CPU会一直等待GPU发出接到命令的回复,如果柱状图很高, 那就意味着你给GPU太多的工作,太多的负责视图需要OpenGL命令去绘制和处理.
解决方案:
1. 从设计根本上简化页面的复杂度
2. 在view层级相同的情况下,尽量使用LinearLayout代替RelativeLayout 原因是RelativeLayout是相对布局,在测量的时候会对子view(child)分别进行横向和纵向的两次测量才能确定相对位置,而LinearLayout顾名思义线性布局,我们设置了方向后,在不使用weight属性时只对view测量一次就可以确定子view的位置。这里强调的是层级相同的情况下!如果布局特别复杂,单纯的使用LinearLayout则会导致层级过深,那采用RelativeLayout比较好,但是,使用ConstraintLayout约束布局代替RelativeLayout绘制速度更快,更灵活不需要嵌套很多层,可以有效的减少布局层级!!! ConstraintLayout性能详解
3. 使用Merge标签来减少重复布局,当一个layout包含另一个layout时,只能用在布局文件的根节点上。简单明了的解释+例子
4. view的属性可以优化的地方:
- tools属性下的方法:
tools:text="张三";
tools:background="@tools:sample/backgrounds/scenic"等 - 显示隐藏尽量用gone代替invisible,因为gone不绘制,invisible绘制后隐藏。(待网友补充)
2、内存问题 方向:
存在问题:内存泄漏、内存溢出、内存浪费等
内存泄漏相关问题:
1. 单例模式导致内存泄漏:单例的静态特性使得它的生命周期跟APP的生命周期一样长,如果一个对象已经没有用处了但是单例还持有它的引用,应用程序的整个生命周期都不能回收, 从而导致内存泄露。构造单例尽量别使用Activity的引用,否则Activity关闭后单例模式还持有该Activity的引用使得Activity得不到回收,会导致内存泄漏,优化案例是采用application中的content。
2. 静态变量导致内存泄漏:静态持有变量很多是因为其使用的生命周期不一致而导致内存泄露,static指向的内存引用,GC永远不会回收,优化方案是尽量少使用,不用时给它重置为null使其不再持有。
3. 非静态内部类导致内存泄漏:非静态内部类的默认持有外部类的引用,当内部类的生命周期比外部类还要长时就会导致内存泄漏。典型场景可以看一下此篇:Handler详解,优化方案:静态内部类+弱引用+销毁时将销毁handler的回调和发送消息移除掉。
4. 资源对象及时关闭导致内存泄漏:在使用IO、File流或者Sqlite、Cursor等资源时要及时关闭。原因是这些资源在进行读写操作时通常使用了缓冲,如果不及时关闭,这些缓冲会一直被占用从而得不到释放,导致内存泄漏。
5. 未取消注册或回调导致内存泄漏:比如在activity中注册广播,如果activity销毁后不取消注册,这个广播会一直存在系统中。
6. 动画导致内存泄漏:动画是一个耗时操作,如果启动了动画后,在页面或视图销毁时没有调用cancle销毁动画,这个动画虽然看不见了但会一直不断地播下去,动画引用的view,view引用的activity无法正常释放造成内存泄漏。
7. WebView造成的内存泄漏:造成的原因是加载网页后长期占用内存不能被释放,WebView控件会持有activity引用,activity销毁后WebView持有的引用得不到释放,优化方式是做好销毁工作或采用成熟的开源WebView库。
内存溢出相关问题:
内存空间不够,导致内存溢出OOM(内存泄漏多了或者直接就不够用,多在于图片等大资源)
查询图片不加载到内存中:Android中Bitmap有四种图片色彩模式:
ALPHA_8:每个像素需要占用内存中的1byte
RGB_565:每个像素需要占用内存中的2byte
ARGB_4444:每个像素需要占用内存中的2byte
ARGB_8888:每个像素需要占用内存中的4byte
我们创建Bitmap时,默认的色彩模式是ARGB_8888的,这种色彩模式是质量最高的,当然这样的模式占用的内存也最大。
应用瘦身
1. 只使用一套图片,xxhdpi : 1080P ;
2. 资源图 转 webp格式, WebP既支持有损压缩也支持无损压缩, 谷歌(google)开发的一种旨在加快图片加载速度的图片格式
3. 代码逻辑简化、无用文件、无用依赖库
4. 微信的安装包压缩。
5. Android设备的CPU类型(ABIs):
armeabi-v7a: 第7代及以上的 ARM 处理器。2011年15月以后的生产的大部分Android设备都使用它.
arm64-v8a: 第8代、64位ARM处理器,很少设备,三星 Galaxy S6是其中之一。
armeabi: 第5代、第6代的ARM处理器,早期的手机用的比较多。
x86: 平板、模拟器用得比较多。
x86_64: 64位的平板。
ndk {
abiFilters "armeabi-v7a"
// abiFilters "armeabi-v7a","x86"
}
未完待续。。。