最近遇到一个很奇怪的问题,团队开发的app在一般安卓手机上运行正常,但是在华为荣耀8、nova青春版这两款手机中却异常卡顿,系统均是android 7.0。其中主页面及重要的页面耗时多达5s,简直不能忍受。
真的有无从下手的感觉。首先能想到的是对比竞品或其他第三方app,然并卵,其他app表现正常,运行流畅。这app卡顿的锅就不能甩给华为的android系统了。
接着去找华为终端的同学求救,收获了。。。的回复。他建议我看下trace分析卡顿原因,脑袋突然不灵光的我质问:都没有产生anr,没有traces.txt产生啊!!!还好后来想起他说的是性能分析的traceview,这才踏上正轨开始分析问题。
打开Android Device Monitor开始分析关键页面启动的耗时,使用方法我就不介绍了,网上都可以找到。上图就是抓到的一个trace文件,可以看到排名靠前的耗时都是系统方法,Handler,LayoutInflater,updateConfiguration等。挨个检查靠前方法的parent,children调用,终于在Resources.updateConfiguration这处发现了不寻常的地方。
可以看到Parents的三处调用,都是我们项目工程自定义的Activity。观看源码,均重写了getResource方法,代码如下:
/**
* 重写此方法目的是app不随系统字体变化
* @return Resources
*/
@Override
public Resources getResources() {
Resources res = super.getResources();
Configuration config = new Configuration();
config.setToDefaults();
res.updateConfiguration(config, res.getDisplayMetrics());
return res;
}
根据前人注释可知,这段代码是为了保证app的字体不随系统字体的变化而变化,这也是网上常见的解决方案。为了确定是否是这段代码导致app界面启动卡顿,我将代码注释后重新编译运行。运气不错,界面启动速度从5s下降到了700毫秒左右,这段代码竟然是卡顿的元凶。
确实updateConfiguration是耗时的操作,尤其在华为荣耀8,nova的手机上。getResource在界面绘制时频繁调用,导致updateConfiguration调用的太频繁。解决的思路就是减少updateConfiguration的调用次数。
根据系统更改字体大小的原理可知,android通过修改Configuration的fontScale的数值来实现字体大小的变化。正常字体大小的fontScale为1。可讲上述代码优化为如下代码:
@Override
public Resources getResources() {
Resources res = super.getResources();
if (res.getConfiguration().fontScale != 1) {//非默认值
Configuration newConfig = new Configuration();
newConfig.setToDefaults();//设置默认
res.updateConfiguration(newConfig, res.getDisplayMetrics());
}
return res;
}
经过测试,该方案的界面启动速度也维持在700毫秒左右。经过这个小小的改动,界面启动速度从5s-》700毫秒,收益时巨大的。后续也会花时间继续优化界面的启动速度,traceView工具用起来!
参考文档:
Android系统字体大小如何影响app的字体大小?
Android 解决APP字体随系字体大小改变造成的布局错位问题。
关于网上解决Android4.x系统设置字体大小导致应用布局混乱引起的问题