这期内容当中小编将会给大家带来有关Android如何发现应用卡顿,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
常用的方式是使用亚行SurfaceFlinger服务和亚行gfxinfo功能,在自动化操作应用的过程中,使用亚行获取数据来监控程序的流畅情况,发现出现出现卡顿的时间段,寻找出现卡顿的场景和操作。
<强>方式1:亚行壳dumpsysSurfaceFlinger 强>
使用“亚行壳dumpsysSurfaceFlinger& # 39;命令即可获取最近127帧的数据,通过定期执行亚行命令,获取帧数来计算出帧率FPS。
<强>方式2:亚行壳dumpsys gfxinfo 强>
使用“亚行壳dumpsys gfxinfo& # 39;命令即可获取最新128帧的绘制信息,详细包括每一帧绘制的画,过程,执行三个过程的耗时,如果这三个时间总和超过16.6毫秒即认为是发生了卡顿。
已有的两种方案比较适合衡量回归卡顿问题的修复效果和判断某些特定场景下是否有卡顿情况,然而,这样的方式有几个明显的不足:
- <李>一般很难构造实际用户卡顿的环境来重现;李> <李>这种方式操作起来比较麻烦,需编写自动化用例,无法覆盖大量的可疑场景,测试重现耗时耗人力;李> <>李无法衡量静态页面的卡顿情况,李> <李>出现卡顿的时候应用无法及时获取运行状态和信息,开发定位困难。李>
随着对Android源码的深入研究,也有了其他两种比较方便的方式,并且这两种方式侵入性小,占用内存低,能够更好的用在实际场景中:
- <李>利用UI线程的电影打印的日志匹配。李> <李>使用编排。李FrameCallback >
Android主线程更新UI。如果界面1秒钟刷新少于60次,即FPS小于60岁的用户就会产生卡顿感觉。简单来说,Android使用消息机制进行UI更新,UI线程有个电影,在其循环方法中会不断取出消息,调用其绑定的处理程序在UI线程执行。如果在处理程序的dispatchMesaage方法里有耗时操作,就会发生卡顿。
下面来看下电影。循环()的源码
公共静态无效循环(){ 最后的电影我=myLooper (); 如果(我==null) { 把新的RuntimeException(“没有电影;Looper.prepare()触动他们# 39;t>/* * *控制日志消息的处理这个电影。如果 *启用,将写入日志消息& lt; var> printer *开始和结束的每条消息调度,确定 *目标处理程序和消息内容。 * * @param打印机的打印机对象将收到日志消息,或 *空禁用消息日志记录。 */最后公共类电影{ 私人打印机mLogging; 公共空间setMessageLogging (@Nullable打印机的打印机){ mLogging=打印机; } } 公共接口的打印机{ 空白println (String x); }
尺蠖的mLogging是私有的,并且提供了setMessageLogging (@Nullable打印机的打印机)的方法,所以我们可以自己实现一个打印机,在通过setMessageLogging()方法传入即可,代码如下:
公共类BlockDetectByPrinter { 公共静态孔隙start () { Looper.getMainLooper ()。setMessageLogging(新打印机(){ 私有静态最终字符串开始=?在在在在在Dispatching"; 私有静态最终字符串结束=? lt; & lt; & lt; & lt; & lt;Finished"; @Override 公共空间println (String x) { 如果(x.startsWith(开始)){ .startMonitor LogMonitor.getInstance () (); } 如果(x.startsWith(结束)){ .removeMonitor LogMonitor.getInstance () (); } } }); } }
设置了日志后,循环方法会回调日志记录。println打印出每次消息执行的时间日志:“在在在在在调度”和“& lt; & lt; & lt; & lt; & lt;完成“.BlockDetectByPrinter的使用则在应用程序的公共类LogMonitor> { 私有静态最终字符串标签=癓ogMonitor"; 私有静态LogMonitor sInstance=new LogMonitor (); 私人HandlerThread mLogThread=new HandlerThread (“log"); 私人处理器mIoHandler; 私有静态最终长TIME_BLOCK=200升; 私人LogMonitor () { mLogThread.start (); mIoHandler=new处理程序(mLogThread.getLooper ()); } 私有静态Runnable mLogRunnable=new Runnable () { @Override 公共空间run () { StringBuilder某人=new StringBuilder (); 异常堆栈StackTraceElement []=Looper.getMainLooper () .getThread () .getStackTrace (); (StackTraceElement s:加亮){ sb.append (s.toString () +“\ n"); } 日志。e(标签,sb.toString ()); } }; 公共静态LogMonitor getInstance () { 返回sInstance; } 公共布尔isMonitor () { 返回mIoHandler.hasCallbacks (mLogRunnable); } 公共空间startMonitor () { mIoHandler。postDelayed (mLogRunnable TIME_BLOCK); } 公共空间removeMonitor () { mIoHandler.removeCallbacks (mLogRunnable); } }