今天看啥  ›  专栏  ›  pengyu6612

Android性能优化

pengyu6612  · 掘金  ·  · 2021-04-16 23:00
阅读 17

Android性能优化

一.高性能App标准:快,稳,省,小

1.快:使用时避免出现卡顿,响应速度快,减少用户等待时间,满足用户期望; 2.稳:降低crash率和ANR率,不要在用户使用过程中崩溃和无响应; 3.省:节省流量和耗电,减少用户使用成本,避免使用时手机发烫; 4.小:安装包小可以降低用户的安装成本;

二.优化范围:卡顿,内存,耗电,网络,apk等方面进行优化

1.卡顿优化:

a.卡顿场景:

1.UI绘制及刷新;
2.启动(安装启动,冷启动,热启动);
3.跳转:页面间切换,前后台切换;
4.响应:按键,系统事件,滑动;
复制代码

b.卡顿根因:

1.界面绘制:
   1).layout复杂,不能在16ms内完成渲染,导致丢帧;
   2).View的过度绘制,导致某些像素在同一帧时间内被绘制多次;
   3).动画在同一时间执行的次数多,导致CPU或GPU负载过重;
 2.数据处理:
   1).耗时操作在UI线程处理;
   2).频繁的GC操作;
   
复制代码

c.卡顿优化:

 1.布局优化:
   1).合理使用LinerLayout,RelativeLayout,,FrameLayout,ConstraintLayout等布局容器;
   2).使用<include>标签来进行布局复用;
   3).使用<merge>标签去除多余层级;
   4).使用ViewStub来提高加载速度;
   5).避免GPU过度绘制:
      a.产生原因:
        1.在XML布局中,控件有重叠其都有设置背景;
        2.View的onDraw()方法在同一区域绘制多次;
      b.解决方案:
        1.移除不需要的background;
        2.在自定义View的onDraw()方法中,用canvas.clipRect()来指定绘制的区域,防止重叠的组件发生过度绘制;
     
 2.启动优化:
   1).UI布局:应用一般会有闪屏页,优化闪屏页的UI布局,可通过Profile GPU Rendering检测丢帧情况;
   2).启动加载数据逻辑优化:可采用分部加载,异步加载,延期加载策略来提高应用启动速度;
   3).数据准备:数据初始化分析,加载数据可考虑用线程初始化等策略;
   
 3.合理的刷新机制:
   1).尽量减少刷新次数;
   2).尽量避免后台有高的CPU线程运行;
   3).缩小刷新区域;
   
 4.其他:实现动画时,需要根据不同的场景选择合适的动画框架来实现;有些情况下可使用硬件加速方式来提高流畅度;
 
复制代码

d.分析和解决工具:

 1.Profile GPU Rendering:用于查找渲染有问题的界面;
 2.Systrace:用于性能数据采样和分析
 功能:1.跟踪系统的I/O操作;
      2.内核工作队列;
      3.CPU负载情况;
      4.各种子系统的运行情况等;
      5.对于UI显示性能:如动画播放不流畅,渲染卡顿等提供了分析数据;
 3.Traceview:用于数据采集和分析
  主要获取两种数据:1.单次执行耗时的方法;2.执行次数多的方法
 4.Hierarchy Viewer:用于检查布局嵌套和绘制的时间;
 5.Android Lint:代码扫描工具,通过代码静态检查来发现代码出现的潜在问题,并给出优化建议;
复制代码

2.内存优化:

a.Android内存管理机制:

1.Java对象生命周期:创建->应用->不可见->不可达->收集->终结->对象空间重新分配;
2.内存分配:实际是对堆的分配和释放,为了控制整个系统的内存控制需要,系统会为每一个应用设置最大限制阈值,超过阈值时会引起内存溢出;
3.内存回收机制:新生代(Edean,Survivor(form,to)),老年代,GC,垃圾回收算法;
复制代码

b.内存泄漏:

 1.根本原因:
  1).简易描述:长生命周期的对象持有短生命周期的对象的引用,导致GC无法回收该对象;
  2).实质理解:没有用的对象到GC Roots是可达的(对象被引用),导致GC无法回收该对象;
 2.常见内存泄漏场景:
  1).单例/静态变量:具有静态性,它的生命周期等于应用的生命周期,若有Context,则应设为Application的context;
  2).匿名内部类/非静态内部类持有外部类的引用:handler使用为静态内部类,使用弱引用;rxjava等;
  3).资源未关闭:IO操作,Cursor,广播,EventBus等;
  4).集合类:未使用时没及时清理;
  5).WebView:使用一次内存就不会被释放,解决方案:为WebView单独开一个进程,使用AIDL与应用的主进程进行通信;
复制代码

c.内存抖动:

1.根本原因:短时间内频繁地创建对象(可能在循环中创建对象),内存为了应对这种情况,会频繁地进行GC操作;频繁的GC会产生大量的暂停时间,会导致界面绘制时间减少,使得多次绘制一帧的时长超过16ms,产生界面卡顿现象;
复制代码

d.内存溢出:

1.根本原因:是指程序在申请内存时,没有足够的内存空间供其使用;
2.如何避免OOM:
 1).使用更加轻量的数据结构:如使用ArrayMap/SparseArray替代HashMap,HashMap更耗内存,因为它需要额外的实例对象来记录Mapping操作,SparseArray更加高效,因为它避免了Key Value的自动装箱,和装箱后的解箱操作;
 2).便面枚举的使用,可以用静态常量或者注解@IntDef替代;
 3).Bitmap优化:
   a.尺寸压缩:通过InSampleSize设置合适的缩
   b.颜色质量:设置合适的format,ARGB_6666/RBG_545/ARGB_4444/ALPHA_6,存在很大差异
   c.inBitmap:使用inBitmap属性可以告知Bitmap解码器去尝试使用已经存在的内存区域,新解码的Bitmap会尝试去使用之前那张Bitmap在Heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放Bitmap。利用这种特性,即使是上千张的图片,也只会仅仅只需要占用屏幕所能够显示的图片数量的内存大小,但复用存在一些限制,具体体现在:在Android 4.4之前只能重用相同大小的Bitmap的内存,而Android 4.4及以后版本则只要后来的Bitmap比之前的小即可。使用inBitmap参数前,每创建一个Bitmap对象都会分配一块内存供其使用,而使用了inBitmap参数后,多个Bitmap可以复用一块内存,这样可以提高性能;
 4).StringBuilder替代String: 在有些时候,代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”;
 5).避免在类似onDraw这样的方法中创建对象,因为它会迅速占用大量内存,引起频繁的GC甚至内存抖动;
 6).减少内存泄漏也是一种避免OOM的方法;
 
复制代码

e.优化内存空间:

1.对象引用:根据业务需求合理使用 强 软 弱 虚 四种引用类型;
2.减少不必要的内存开销:注意自动装箱,增加内存复用,如:有效利用系统自带的资源,视图复用,对象池,Bitmap对象复用;
3.使用最优的数据类型:如ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等;
4.图片内存优化:可设置图片位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等;
复制代码

f.内存分析工具:

1.Profiler(系统自带):
 1).主要用来观察内存,网络,CPU温度等;
 2).可识别出内存泄漏和内存抖动导致应用的卡顿,ANR和crash;
 3).可生成图表,查看内存的使用情况,还能强制内存回收和跟踪内存分配;
2.MAT
 1).通过DDM或Memory Monitor生成格式为hprof的堆存储文件;
 2).通过深入分析疑似发生内存时所生成的hprof来确定是否发生内存泄漏;
3.LeakCanary:基于MAT开发的内存泄漏插件;
复制代码

3.耗电优化---敬请期待 4.网络优化---敬请期待 5.Apk优化---敬请期待




原文地址:访问原文地址
快照地址: 访问文章快照