本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点
卡顿优化
这里主要介绍卡顿优化方面的布局优化
布局优化
1、 在主线程中,加载SP,或者是缓存加载,JSON解析,可以放到Idelhander
2、 viewpager的懒加载,用viewpager2替换viewpager,方便懒加载
ViewPager.offscreenPageLimit = 2
3、 布局嵌套层级优化时,自定义继承自ViewGroup的View中,如果本身继承自LinearLayout等布局,则可以考虑根布局使用merge标签,如果根布局使用merge标签,在LayoutInfater中必须指定attachToParent为true,否则会崩溃,同时this.addView就不需要了
4、 如果view不一定会显示,此时可以使用 ViewStub 来包裹此View 以避免不需要显示view但是又需要加载view消耗资源。viewstub是一个轻量级的view,它不可见,不用占用资源,只有设置viewstub为visible或者调用其inflflater()方法时,其对应的布局文件才会被初始化。
5、 检测工具: Layout Inspector
过渡渲染
开发者选项--->打开GPU过度绘制开关
- 检查是否重复设置background
布局加载优化
- LayoutInflflater加载xml布局的过程会在主线程使用IO读取XML布局文件进行XML解析,再根据解析结果利用反射创建布局中的View/ViewGroup对象。
- 可以用
Asynclayoutinflater
来异步加载
dependencies {
implementation "androidx.asynclayoutinflater:asynclayoutinflater:1.0.0" }
new AsyncLayoutInflater(this).inflate(R.layout.activity_main, null, new AsyncLayoutInflater.OnInflateFinishedListener() {
@Override public void onInflateFinished(@NonNull View view, int resid, @Nullable ViewGroup parent) {
setContentView(view);
//......
}
});
异步加载注意点:
1、使用异步 inflflate,那么需要这个 layout 的 parent 的 generateLayoutParams 函数是线程安全的;
2、所有构建的 View 中必须不能创建 Handler 或者是调用 Looper.myLooper;(因为是在异步线程中加载的,异步线程默认没有调用 Looper.prepare );
3、AsyncLayoutInflflater 不支持设置 LayoutInflflater.Factory 或者 LayoutInflflater.Factory2;
4、不支持加载包含 Fragment 的 layout
5、如果 AsyncLayoutInflflater 失败,那么会自动回退到UI线程来加载布局
卡顿监控的2种方式:
1、 Looper比较适合在发布前进行测试或者小范围灰度测试然后定位问题
2、 ChoreographerHelper适合监控线上环境的 app 的掉帧情况来计算 app 在某些场景的流畅度然后有针对性的做性能优化
public class ChoreographerHelper {
public static void start() {
if (Build.VERSION.SDK\_INT >= Build.VERSION\_CODES.JELLY\_BEAN) {
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
long lastFrameTimeNanos = 0;
@Override
public void doFrame(long frameTimeNanos) {
//上次回调时间
if (lastFrameTimeNanos == 0) {
lastFrameTimeNanos = frameTimeNanos;
Choreographer.getInstance().postFrameCallback(this);
return;
}
long diff = (frameTimeNanos - lastFrameTimeNanos) / 1_000_000;
if (diff > 16.6f) {
//掉帧数
int droppedCount = (int) (diff / 16.6);
}
lastFrameTimeNanos = frameTimeNanos;
Choreographer.getInstance().postFrameCallback(this);
}
});
}
}
}
App 开发者可以通过以下这些方法监控自身 App 的性能,其中常用的方法如下:
利用 FrameCallback 的 doFrame 回调
利用 FrameInfo 进行监控
使用 :adb shell dumpsys gfxinfo framestats
示例 :adb shell dumpsys gfxinfo com.meizu.flyme.launcher framestats
- 利用 SurfaceFlinger 进行监控
使用 :adb shell dumpsys SurfaceFlinger --latency
示例 :adb shell dumpsys SurfaceFlinger --latency com.meizu.flyme.launcher/com.meizu.flyme.launcher.Launcher#0
- 利用 SurfaceFlinger PageFlip 机制进行监控
使用 : adb service call SurfaceFlinger 1013
备注:需要系统权限
其他卡顿监控的工具
1、 systrace 一般用来检测滑动的情况,有没有卡顿掉帧
2、 BlockCanary卡顿监控原理:跟Looper中message有关,在取出message后,会先调用一个printer打印一个日志,然后执行dispatchMessage方法,再又打印下日志,我们可以通过设置自己的实现printer接口的类,来监听日志打印,根据前后打印的间隔时间,超过阈值就输出日志
总结2种卡顿监控原理
Choreographer 原理:自身的掉帧计算逻辑
BlockCanary原理: 基于 Looper 的性能监控
欢迎关注我的公众号AntDream查看更多精彩文章!