Android性能 - 取经之路_UI

整理自网络

Android性能 - 启动

  • Android程序的启动分类
  • 冷启动
  1. 加载启动app
  2. 展示空白window页面
  3. 创建app进程
  4. 创建app对象
  5. 启动主线程
  6. 创建启动activity对象
  7. 加载view
  8. 布置屏幕
  9. 第一次绘制
  • 启动优化方向
  1. 替换window页面背景 <障眼法>
  2. 避免启动的密集初始化
    常常使用的multiDex初始化,第三方组件初始化
    利用欢迎页和闪屏页时间完成初始化
  3. 避免耗时操作和深嵌套布局

Android性能 - 布局

由于任何原因导致接收到VSYNC信号的时候无法完成本次刷新操作,就会产生掉帧的现象

  • 过度绘制

Android性能 - 取经之路_Java_02

  • 解决
  1. 去掉布局的背景色
  2. 去掉不必要控件的背景色
  • GPU渲染

Android性能 - 取经之路_UI_03

  1. 橙色 :GUP做的任务
  2. 红色 :绘制视图的多少
  3. 浅蓝色 :绘制图片
  4. 深蓝色 :更新视图
  5. 绿色1 :布局测量
  6. 绿色2 :动画
  7. 绿色3 :输入处理
  8. 深绿色: 主线程耗时操作

Android性能 - 内存 (一)

  • Java内存
  1. 方法区:常量,类信息 <线程共享>
  2. 虚拟栈:每个方法由栈帧,存储方法信息 <线程私有,为Java方法服务>
  3. 本地栈:为本地方法服务
  4. 堆: 对象实例所在<线程共享>
  5. 程序计数器: 所执行的字节码行号指示器 <Java方法拥有,本地方法为空>
  • Java内存回收
  1. 标记清除 : 标记回收对象,清除被标记对象 <易产生大量碎片>
  2. 复制算法 :内存一分为二,一个现用,一个备用 <实际可用内存大小缩小为一半>
  3. 标记整理: 标记回收对象,整理(移动)存活对象 <避免内存碎片,避免一半内存的浪费 针对对象存活率较高的老年代>
  4. 分代收集: 根据对象的生命周期划分内存
    堆:
    ​ 新生代 ->大量对象死亡 -> 复制算法
    老年代 ->对象存活率高 -> 标记算法
  • 对象是否回收
  1. 引用计数
    引用对象,计数+1
    引用失效,计数 - 1
    缺点:不能解决相互循环引用
  2. 可达性分析
    以GCroot对象为根节点
    有可达引用链表示对象存活
  • Android内存
  • Dalvik虚拟机
  1. 加入JIT即时编译策略: 缺点①每次启动应用都要编译②运行时更耗电
  • ART虚拟机
  1. AOT编译策略,静态编译,安装程序的时候编译
  2. 改进GC过程
  • 两者混合编译
  1. 程序安装时dex不会被编译
  2. 运行时编译dex
  3. 手机充电或者空闲时进行AOT编译
  • 内存回收
    新生代->老年代->永久代
  • 共享内存
    Zygote的进程fork出来的程序进程
  • 分配和回收内存

Android性能 - 卡顿

60帧合适的显示速度,16ms内显示界面布局表示流畅画面

卡顿时候,帧率下降到30等,很明显的卡顿

卡顿的原因

  • UI线程中的耗时操作
  1. I/O读写
  2. 数据库访问
  3. 网络请求
  • 布局不合理
  1. 控件数量多
  2. 嵌套深
  3. overdraw
  • 内存异常
  1. 内存泄漏
  2. GC次数多 <那么CPU绘制时间就短>
  • 错误的异步操作
  1. 异步线程开启失误

寻找卡顿原因

  • stick mode
    检测程序中违例的情况
  1. 主线程进行I/O操作
  2. 主线程进行网络请求

主要检测两大问题

  1. 线程策略 <线程使用不当>
  2. VM策略 <内存泄漏>

使用

if (IS_DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
StrictMode.setVmPolicy(new VmPolicy.Builder().detectAll().penaltyLog().build());
}

在debug模式下使用

查看日志

Android性能 - 取经之路_UI_04

Android性能 - 异步

异步不包治百病,不正确使用异步会更卡顿

线程调度

  • nice values线程优先级
  1. default UI线程
  2. background 后台线程
  • cgroups
  1. 控制和分离进程组
  • 使用
new Thread(new Runannable()).start()
创建和销毁耗能大
和UI线程具有相同的优先级,出现竞争
匿名内部类持有外部引用,易内存泄漏
缺乏线程管理
private class A extendes AysncTask<in,progress,result>{
onPreExecute();//执行任务前
doInBackground();//线程后台任务
onProgressUpdate();//任务进度
onPostExecute();//UI操作
onCancelled();//取消异步操作
}

in 传入的参数
progress 进度
result 结果

默认串行
匿名内部类持有外部引用,内存易泄漏
Handler handler = new Handler(){
handleMessage(msg);
};

串行执行
默认优先级和UI线程同级,出现竞争

IntentService

ThreadPoolExecutor

Android性能 - 瘦身

  • APK组成
  1. assets/ 静态文件
  2. lib/ os文件
  3. META-INF/ 签名信息
  4. res/ 资源文件
  5. AndroidManifest.xml 配置文件
  6. classes.dex Java字节码的产物
  7. resource.arsc 编译后的二进制资源文件
  1. 移除无用代码
  2. 移除无用库,相同库
  3. 启用Proguard
    稍用,规则繁琐
  4. 缩减方法数
  5. 移除无用资源
layout

drawable
  1. 图片压缩
    压缩网站 https://tinypng.com/
    AndroidStudio插件:​​TinyPngPlugin​​,能够批量地压缩项目中的图片,更加方便。
  2. png转jpg
    png无损
    png体积大
  3. 使用矢量图
    xml, svg
  4. 使用webp
  5. 网络资源
  6. so文件瘦身
  7. 使用7zip进行极限压缩

Android性能 - 电量

  • 工具 Battery Historian
  • 电量优化
  1. CPU时间片
  2. 网络传输
    数据压缩
    传输方式
    请求处理
    无网避免请
  3. GPS

合适的location provider

及时注销监听

模块复用

  1. wake lock 不休眠锁
  2. 传感器

Android性能 - 网络

  • 网络问题
  1. 流量消耗
  2. 电量消耗
  3. 热修复
  4. 弱网
  • 网络监控
  1. network monitor 网络请求
  2. fiddler charles 抓包
  • 优化方向 <速度,流量,成功率>
  1. gzip压缩减少传输
  2. IP直连去除DNS解析
  3. webp格式的图片
  4. 缩略图
  5. 网络缓存
  6. 弱网判断特殊处理

Android性能 - 无响应

  • 分类
  1. 触摸或按键等待
  2. 广播不能规定完成
  3. 服务不能规定完成
  • 原因
  1. 主线程阻塞
  2. IO等待
  3. 其他程序影响
  • 出发场景
  1. 输入5s未响应完毕
  2. 前台广播10s内未完毕,后台20s
  3. 前台服务20s,后台服务200s
  4. 内容提供者publish 10s

Android性能 - Bitmap

  • bitmap内存模型
    Android2.2之前GC执行,主线程暂停;
    Android2.3之后,GC并发执行
    API 10 bitmap像素数据存放在 native内存,对象在dalvik heap;
    3.0~8.0 像素和对象都在native内存;
    8.0~now 像素又移到了native,对象和像素可以同时回收,新增hardware bitmap
  • bitmap回收

2.2.3之前推荐使用bitmap.recycle()

3.0之后复用bitmap

  • bitmap的复用
  • bitmap的加载
  • 推荐使用图片加载框架glide,piccasso等处理图片