注册

Android卡顿优化思路

卡顿优化思路



  • 卡顿原理分析
  • 卡顿流程flow
  • 卡顿概貌分析
  • 卡顿实际数据收集
  • 卡顿优化细节

卡顿原因


屏幕刷新频率高于帧率,帧率低于30


每帧执行流程


Choreographer中维护着四个队列callbacks



  • 输入事件队列
  • 动画队列
  • 绘制队列
  • app添加的frameCallback队列

vysnc信号由SurfaceFlinger中创建HWC触发,通过bitTube技术发送到目标进程,目标进程vsync信号到来时,执行Choreographer中的onVsync回调,最终触发doFrame顺序执行这四条队列中的消息。


bitTube


在linux/unix中,bitTube技术成为socketPair,它通过dup技术复制socket的句柄,传递到目标进程,开启socket的全双工通信。


句柄


在内核中,每一个进程都有一个私有的“打开文件表”,这个表是一个指针数组,每一个元素都指向一个内核的打开文件对象。而fd,就是这个表的下标。当用户打开一个文件时,内核会在内部生成一个打开文件对象,并在这个表里找到一个空项,让这一项指向生成的打开文件对象,并返回这一项的下标作为fd.


ui优化



  • 多余Bg移除
  • ui重叠区域优化 cancas.clipRect
  • 减少ui层级
  • 耗时方法分析与优化
  • 多样式布局采用单一rv处理

webview优化


webview的加载流程


image


webiew初始化



  • 目的是初始化并启动浏览器内核。
  • 提前初始化webview并隐藏 优化126ms

webview 单独进程



  • 单独进程 activity配置
  • 单独进程的交互 webview.addJavascriptInterface(),webview.evalute()

安全性



  • addJavaScriptInterface添加的java对象的方法,需要添加@addJavascriptInterface注解,避免xss攻击

卡顿收集策略


开发卡顿检测StrictMode


private void initStrictMode() {
if (isDebug()) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls() //API等级11,使用StrictMode.noteSlowCode
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyDialog() //弹出违规提示对话框
.penaltyLog() //在Logcat 中打印违规异常信息
.penaltyFlashScreen() //API等级11
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects() //API等级11
.penaltyLog()
.penaltyDeath()
.build());
}
}

线下卡顿检测



  • adb shell dumpsys gfxinfo [packagename]

Applications Graphics Acceleration Info:
Uptime: 205237819 Realtime: 436545102

** Graphics info for pid 5842 [xxxx] **

Stats since: 198741999784549ns
Total frames rendered: 653
Janky frames: 157 (24.04%)
50th percentile: 9ms
90th percentile: 34ms
95th percentile: 53ms
99th percentile: 200ms
Number Missed Vsync: 46
Number High input latency: 268
Number Slow UI thread: 76
Number Slow bitmap uploads: 3
Number Slow issue draw commands: 8
Number Frame deadline missed: 92


  • 通过gpu绘制条形柱分析

条形柱共分为8种颜色,绿色和蓝色部分是异步应用能够优化的部分。包括其他处理 - 输入 - 动画 - travel
image


BlockCanary检测卡顿


在ActivityThread.main中的Looper大循环中,Looper.looponce会不断从消息队列中取出消息派发出去,并在前后通过logging打印了两个日志,我们通过设置自定义的logger,在两部分日志的时间差与30ms做对比,如果超过30ms,认为是卡顿。


logging.println(">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what);
msg.target.dispatchMessage(msg);
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);

卡顿分析信息收集



  • Debug.startMethodTracing 收集具体的卡顿方法
  • 查看trace文件 根据bottomup分析具体的耗时方法
  • 火焰图,横轴是调用方法耗时,纵轴是调用深度
  • 调用图,调用链以及方法耗时

线上卡顿分析与收集


在ActivityThread.main中的Looper大循环中,Looper.looponce会不断从消息队列中取出消息派发出去,并在前后通过logging打印了两个日志,我们通过设置自定义的logger,在两部分日志的时间差与30ms做对比,如果超过30ms,认为是卡顿。将主线程堆栈信息写入到缓存文件并异步发送到日志后台。


常见的卡顿问题


sharepreference



  • 首次读取写入会loadxml到内存
  • sp文件修改是全量读写的
  • commit异步写入,通过CountdownLatch阻塞等待结果
  • apply延迟100ms写入,无返回结果
  • 主线程ANR,sp的修改会先体现在内存中,然后往QueueWorker中加入磁盘异步写数据的任务,但是会在Activity.onResume以及Service.onstartCommand等方法中增加waitToFinish等待磁盘写入完成的代码。
  • 解决方案使用MMKV
  • 尽量拆分小的xml

主线程操作文件


主线程网络操作


作者:八道
链接:https://juejin.cn/post/7065128832616890398
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册