Android 布局优化

93 阅读3分钟

一个视图绘制到屏幕的流程大致为:

  1. 解析、构建视图对象
  2. 组装需要绘制的视图树
  3. 完成视图树中所有视图的测量、定位、绘制
  4. GPU将视图树中需要渲染的内容解码成Graphic Buffer;
  5. Surfaceflinger将各图层的字节码合并;
  6. 垂直同步信号获取合并后的渲染字节;
  7. 最后视图在屏幕上绘制出来;

所以优化布局可以从以下几个方向着手:

  1. 使用代码创建视图布局替代使用xml解析的方式 可以减少使用xml创建视图布局时,解析xml内容以及反射构建对象带来的额外耗时,但是这样大大减少了视图的直观性,增加了布局构建的代码量和难度。可以尝试使用类似X2C一类的框架,在编译期间就xml文件解析成对应的java代码。不过由于编译期间无法获取系统style,X2C只支持应用内style。另外使用compose一类的声明式编程也一种不错的选择。
  2. 异步构建; 在子线程中完成视图的解析、构建,然后交到主线程进行加载,例如使用谷歌提供的AsyncLayoutInflater。
  3. 使用merge标签减少引用布局文件时产生多余的布局嵌套 需要注意:1)merge标签只可以作为xml内布局的根节点;2)引用含merge标签的xml文件时,必须放入viewGroup中;
  4. 使用RelativeLayout或者ConstraintLayout解决复杂嵌套 RelativeLayout需要测量2次才能得到实际尺寸,FrameLayout或LinearLayout在不使用weight时只需测量一次,LinearLayout使用weight时需要测量2次;
  5. 使用确定的宽高代替wrap_content 前提是对应视图的高度计算简单,比如宽高为固定大小,如果过于复杂不如直接交给系统计算;
  6. 使用ViewStub标签占位 ViewStub是一个宽高都为0且默认不可见的视图,仅作节点占位用;当调用infale()或者setVisibility(View.VISIBLE),ViewStub将从父视图中移除并替换为对应的视图。
  7. 避免过度绘制 指屏幕上某个像素在同一帧的时间内被绘制了多次;这将导致CPU和GPU资源的浪费;我们可以在手机的设置—->开发者选项—->打开"调试GPU过度绘制" 查看过度绘制情况;过度绘制分为4个级别,分别用一种颜色来表示:蓝色:代表同一个像素点多绘制了1次;淡绿:代表同一个像素点多绘制了2次;淡红:代表同一个像素点多绘制了3次;深红:代表同一个像素点多绘制了4次以上。
  8. 视图内容分段加载 避免因为准备视图数据消耗过多的时间或内存,内存消耗过多也会因为频繁GC而导致卡顿;只加载当前需要展示的内容,其他内容异步读取,或者按需读取;例如,加载一千万条数据时,可考虑只加载当前的100条、之前的100条、之后的100条,随着浏览变化更改加载内容;或者加载大图时,可使用BitmapRegionDecoder分块加载图片内容;
  9. 使用单独的渲染线程 自己开发一套子线程ViewRootImpl,或者利用SurfaceView或TextureView的独立渲染线程,减少主线程负担;
  10. 提高复用能力 使用include提取公用布局;合理使用RecyclerView,滚动方向的尺寸不要使用wrap_content;