抑郁症健康,内容丰富有趣,生活中的好帮手!
抑郁症健康 > 【Android 性能优化】布局渲染优化 ( CPU 渲染优化 | 减少布局的嵌套 | 测量

【Android 性能优化】布局渲染优化 ( CPU 渲染优化 | 减少布局的嵌套 | 测量

时间:2023-11-08 06:20:34

相关推荐

文章目录

一、 减少布局嵌套二、 布局渲染时间测量1. FrameMetrics 使用流程2. FrameMetrics 参数解析3. FrameMetrics 代码示例三、 布局渲染优化总结

一、 减少布局嵌套

在 【Android 性能优化】布局渲染优化 ( GPU 过度绘制优化总结 | CPU 渲染过程 | Layout Inspector 工具 | View Tree 分析 | 布局组件层级分析 ) 博客中引入了 CPU 渲染优化 , CPU 渲染优化的核心就是减少布局嵌套 , 布局嵌套使用 Android Studio 中的 Layout Inspector 工具进行查看 ;

CPU 渲染的优化的核心就是减少布局的嵌套 , 推荐使用约束布局进行开发 , 只有一层嵌套的布局 ;

减少布局的嵌套 , 能极大减少 UI 组件测量 , 摆放 , 生成 UI 组件的时间 , 这样就可以减少 CPU 渲染时间 , 使整个渲染过程时间降低 , 尽可能的压缩在 16ms 以内 , 保证 Vsync 信号到来时 , 渲染已经完毕 , 可以在屏幕中绘制这些布局 ;

能够被优化的布局 :假如父布局中只有一个子布局 , 子布局中有若干组件 , 那么可以直接将子布局的组件放在父布局中 , 将子布局这个层级干掉 , 或者将父布局层级删除 ;

一个父布局没有分支的布局 , 只有一个子布局 , 那么大概率可以优化删除父布局或子布局中的一个 , 两者保留一个 ;

强烈推荐使用 ConstraintLayout 约束布局 , 没有以上布局嵌套问题 ;

二、 布局渲染时间测量

如果使用 可以直接在该工具中查看布局渲染时间 , 但是该工具停止维护 , 使用老版本的 Android Studio 可以使用该工具 ;

Google 官方推荐使用 OnFrameMetricsAvailableListener 测量布局渲染时间 ;

1. FrameMetrics 使用流程

FrameMetrics 使用流程 :

① 创建测量线程 :测量的过程肯定是要放在线程中执行 , 这里创建 HandlerThread 线程 ; 该线程创建后直接启动即可 ;

HandlerThread handlerThread = new HandlerThread("FrameMetrics");handlerThread.start();

② 创建 Handler :测量时 , 需要将 Handler 对象传递到 addOnFrameMetricsAvailableListener 方法中 , 与 Window.OnFrameMetricsAvailableListener 监听器一起设置 ;

Handler handler = new Handler(handlerThread.getLooper());

③ 注册监听器 :向 Activity 界面的 Window 窗口对象 , 添加监听器 , 同时设置 Handler , 渲染测量过程在该 Handler 所在线程执行 ;

getWindow().addOnFrameMetricsAvailableListener(new Window.OnFrameMetricsAvailableListener(){// 省略实现内容 ... }, handler);

④ 回调方法中获取渲染时间 :FrameMetrics frameMetrics 参数中封装了 121212 个渲染性能参数属性 , 可以自行

2. FrameMetrics 参数解析

FrameMetrics 参数解析 :

3. FrameMetrics 代码示例

代码示例 :

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {// 渲染性能测量renderingPerformanceMeasurement();super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}/*** 渲染性能测量*/public void renderingPerformanceMeasurement(){HandlerThread handlerThread = new HandlerThread("FrameMetrics");handlerThread.start();Handler handler = new Handler(handlerThread.getLooper());// 24 版本以后的 API 才能支持该选项if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {// 整个渲染过程测量都在 HandlerThread 线程中执行getWindow().addOnFrameMetricsAvailableListener(new Window.OnFrameMetricsAvailableListener(){@Overridepublic void onFrameMetricsAvailable(Window window,FrameMetrics frameMetrics,int dropCountSinceLastInvocation) {// 帧渲染测量完毕后, 会回调该方法// 渲染性能参数都封装在 FrameMetrics frameMetrics 参数中// 先拷贝一份, 之后从拷贝的数据中获取对应渲染时间参数FrameMetrics fm = new FrameMetrics(frameMetrics);// 1. 动画执行回调时间, 单位纳秒Log.i("FrameMetrics", "ANIMATION_DURATION : " +fm.getMetric(FrameMetrics.ANIMATION_DURATION));// 2. 向 GPU 发送绘制命令花费的时间, 单位纳秒Log.i("FrameMetrics", "COMMAND_ISSUE_DURATION : " +fm.getMetric(MAND_ISSUE_DURATION));// 3. 将组件树 ( View Hierarchy ) 转为显示列表 ( DisplayLists )// 计算过程所花费的时间, 单位纳秒Log.i("FrameMetrics", "DRAW_DURATION : " +fm.getMetric(FrameMetrics.DRAW_DURATION));// 4. 绘制的该帧是否是第一帧, 0 是, 1 不是// 第一帧渲染会慢一些// 第一帧不会引发动画中的跳帧问题, 这些问题都会被窗口动画隐藏// 不必进行显示过程中的 jank 计算Log.i("FrameMetrics", "FIRST_DRAW_FRAME : " +fm.getMetric(FrameMetrics.FIRST_DRAW_FRAME));// 5. 处理输入事件花费的时间, 单位纳秒Log.i("FrameMetrics", "INPUT_HANDLING_DURATION : " +fm.getMetric(FrameMetrics.INPUT_HANDLING_DURATION));// 6. 该值是个时间戳, 表示该帧的 vsync 信号发出时间// 这个时间是当前帧的预期开始时间// 如果该时间与 VSYNC_TIMESTAMP 时间戳不同// 那么说明 UI 线程被阻塞了, 没有及时响应 vsync 信号Log.i("FrameMetrics", "INTENDED_VSYNC_TIMESTAMP : " +fm.getMetric(FrameMetrics.INTENDED_VSYNC_TIMESTAMP));// 7. 组件树 ( view hierarchy ) 测量 ( measure ) 和摆放 ( layout ) 花费的时间// 单位 纳秒Log.i("FrameMetrics", "LAYOUT_MEASURE_DURATION : " +fm.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION));// 8. CPU 传递多维向量图形数据给 GPU 花费的时间, 单位纳秒Log.i("FrameMetrics", "SWAP_BUFFERS_DURATION : " +fm.getMetric(FrameMetrics.SWAP_BUFFERS_DURATION));// 9. 显示列表 ( DisplayLists ) 与显示线程同步花费的时间, 单位纳秒Log.i("FrameMetrics", "SYNC_DURATION : " +fm.getMetric(FrameMetrics.SYNC_DURATION));// 10. CPU 渲染到传递到 GPU 所用的总时间, 上述所花费的有意义的时间之和// 单位纳秒Log.i("FrameMetrics", "TOTAL_DURATION : " +fm.getMetric(FrameMetrics.TOTAL_DURATION));// 11. UI 线程响应并开始处理渲染的等待时间, 一般是 0, 如果大于 0 说明出问题了Log.i("FrameMetrics", "UNKNOWN_DELAY_DURATION : " +fm.getMetric(FrameMetrics.UNKNOWN_DELAY_DURATION));// 12. vsync 信号发出的时间戳, 该时刻 GPU 应该进行绘制, 间隔 16ms// 同时 CPU 开始渲染Log.i("FrameMetrics", "VSYNC_TIMESTAMP : " +fm.getMetric(FrameMetrics.VSYNC_TIMESTAMP));}}, handler);}}}

打印结果 :

-06-25 13:19:05.339 14179-14229/kim.hsl.rtmp I/FrameMetrics: ANIMATION_DURATION : 3854-06-25 13:19:05.339 14179-14229/kim.hsl.rtmp I/FrameMetrics: COMMAND_ISSUE_DURATION : 101644281-06-25 13:19:05.339 14179-14229/kim.hsl.rtmp I/FrameMetrics: DRAW_DURATION : 9981616-06-25 13:19:05.339 14179-14229/kim.hsl.rtmp I/FrameMetrics: FIRST_DRAW_FRAME : 1-06-25 13:19:05.339 14179-14229/kim.hsl.rtmp I/FrameMetrics: INPUT_HANDLING_DURATION : 50625-06-25 13:19:05.339 14179-14229/kim.hsl.rtmp I/FrameMetrics: INTENDED_VSYNC_TIMESTAMP : 164845526994092-06-25 13:19:05.339 14179-14229/kim.hsl.rtmp I/FrameMetrics: LAYOUT_MEASURE_DURATION : 154012359-06-25 13:19:05.339 14179-14229/kim.hsl.rtmp I/FrameMetrics: SWAP_BUFFERS_DURATION : 1569062-06-25 13:19:05.339 14179-14229/kim.hsl.rtmp I/FrameMetrics: SYNC_DURATION : 405729-06-25 13:19:05.340 14179-14229/kim.hsl.rtmp I/FrameMetrics: TOTAL_DURATION : 268872818-06-25 13:19:05.340 14179-14229/kim.hsl.rtmp I/FrameMetrics: UNKNOWN_DELAY_DURATION : 639354-06-25 13:19:05.340 14179-14229/kim.hsl.rtmp I/FrameMetrics: VSYNC_TIMESTAMP : 164845526994092-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: ANIMATION_DURATION : 281042-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: COMMAND_ISSUE_DURATION : 1590885-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: DRAW_DURATION : 57-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: FIRST_DRAW_FRAME : 1-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: INPUT_HANDLING_DURATION : 38646-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: INTENDED_VSYNC_TIMESTAMP : 164845543729270-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: LAYOUT_MEASURE_DURATION : 6619844-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: SWAP_BUFFERS_DURATION : 908230-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: SYNC_DURATION : 51302-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: TOTAL_DURATION : 284281446-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: UNKNOWN_DELAY_DURATION : 274133736-06-25 13:19:05.371 14179-14229/kim.hsl.rtmp I/FrameMetrics: VSYNC_TIMESTAMP : 164845810395926-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: ANIMATION_DURATION : 206980-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: COMMAND_ISSUE_DURATION : 2708386-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: DRAW_DURATION : 86823-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: FIRST_DRAW_FRAME : 0-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: INPUT_HANDLING_DURATION : 51302-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: INTENDED_VSYNC_TIMESTAMP : 164845828222860-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: LAYOUT_MEASURE_DURATION : 685260-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: SWAP_BUFFERS_DURATION : 859895-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: SYNC_DURATION : 537292-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: TOTAL_DURATION : 5902960-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: UNKNOWN_DELAY_DURATION : 545772-06-25 13:19:05.377 14179-14229/kim.hsl.rtmp I/FrameMetrics: VSYNC_TIMESTAMP : 164845828222860

三、 布局渲染优化总结

1 . 背景问题 :主题的背景 , 布局的背景 , 组件的背景 , 都需要特别主题 , 每次添加背景 , 都会增加一次绘制 ;

2 . 布局嵌套 :推荐使用约束布局 ; 如果某个容器布局只有一个子容器 , 那么可以删除一层嵌套 ;

3 . merger 使用 :如果是 FrameLayout 布局 , 使用 merger 可以减少一层嵌套 ;

4 . 布局包含 :布局文件中尽量使用 include 包含其它布局 , 如标题栏 Toolbar 组件 , 这样 GPU 中缓存一次之后 , 之后的界面再加载该 Toolbar 组件时 , 直接复用 GPU 中缓存的纹理数据 ;

5 . 自定义组件裁剪 :在 Canvas 绘制重叠时 , 使用裁剪后的画布绘制 ;

【Android 性能优化】布局渲染优化 ( CPU 渲染优化 | 减少布局的嵌套 | 测量布局绘制时间 | OnFrameMetricsAvailableListener | 布局渲染优化总结 )

如果觉得《【Android 性能优化】布局渲染优化 ( CPU 渲染优化 | 减少布局的嵌套 | 测量》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。