Android布局UI优化

卡顿罪魁祸首

UI卡顿就是Android在界面渲染时丢帧。 Android系统要求每一帧都要在 16ms 内绘制完成,在这个时间内界面就是流畅的(能够达到流畅的画面所需要的60fps)

丢帧的各种原因:

  • layout 太过复杂,层次过多,UI 上有层叠太多的绘制单元,过度绘制
  • CPU 或者 GPU 负载过重
  • 动画执行的次数过多
  • 频繁 GC,主要是内存抖动
  • UI 线程执行耗时操作(要在子线程执行耗时操作)

分析与建议解决

Layout太过复杂,层次过多,UI 上有层叠太多的绘制单元,过度绘制

对于我们Layout文件,层级越多,Android在初始化他们时,也就是渲染时就越浪费时间。所以布局的优化其实说白了就是减少层级,越简单越好,减少overdraw( 过度绘制是一个术语,表示某些组件在屏幕上的一个像素点的绘制次数超过 1 次),就能更好的突出性能。

LinearLayout和RelativeLayout 性能大比拼:

LinearLayout 在 measure 的时候,在横向或者纵向会去测量子 View 的宽度或高度,且只会测量一次。但是当设置 layout_weight 属性的时候会去测量两次才能获得精确的展示尺寸。

RelativeLayout 在 measure 的时候会在横向和纵向各测量一次。也就是需要两次度量来确保自己处理了所有的布局关系。

高能:如果带有 layout_weight 属性的 LinearLayout 或者 RelativeLayout 被套嵌使用,measure 所费时间可能会呈指数级增长(两个套嵌的叶子 View 会有四次 measure,三个套嵌的叶子 view 会有8次的 measure)。为了缩短这个时间,保持树形结构尽量扁平(深度低),而且尽量要移除所有不需要渲染的 View。

  • 尽量避免在视图层级的顶层使用相对布局 RelativeLayout。相对布局 RelativeLayout 比较耗资源,因为一个相对布局 RelativeLayout需要两次度量来确保自己处理所有的布局关系;
  • 布局层级顶层建议使用线性布局 LinearLayout 代替相对布局 RelativeLayout,因为线性布局 LinearLayout 性能要更高一些;
  • 当LinearLayout 需要嵌套才能实现的复杂布局,建议使用RelativeLayout;
  • 尽量避免使用 layout_weight 属性。(但是的确在等分布局时挺好用的)

其他布局优化

  • include标签 (引入布局)
  • merge标签(简单粗暴点回答:干掉一个View层级。主要作用是为了防止在引用布局文件时产生多余的布局嵌套)
  • ViewStub标签(一句话总结:高效占位符。ViewStub是View的一种,但是它没有大小,没有绘制功能,也不参与布局,资源消耗非常低。主要作用是把我们不常用的View在我们需要的时候才去加载)

Android最新的布局方式ConstaintLayout

ConstraintLayout允许在不适用任何嵌套的情况下创建大型而又复杂的布局。它与RelativeLayout非常相似,所有的View都依赖于兄弟控件和父控件的相对关系。但是,ConstraintLayout比RelativeLayout更加灵活,支持比例布局,目前在Android Studio中使用也十分方便。

过度绘制

过度绘制:过渡绘制是一个术语,表示某些组件在屏幕上的一个像素点的绘制次数超过 1 次。过度绘制导致的问题是花费太多的时间去绘制那些堆叠在下面的、用户看不到的东西,浪费 CPU 周期和渲染时间。

优化:

  • 去除重复或者不必要的 background
  • 点击态中的 normal 尽量设置成 transparent
  • 去除 window 中的 background(可以通过处理 decorView 或者设置 Theme 的方式)

CPU 或者 GPU 负载过重

UI 线程是应用的主线程,很多的性能和卡顿问题是由于在主线程中做了大量的工作。除了主线程外,子线程占用过多 CPU 资源也会导致渲染性能问题。

在 UI 渲染的过程中,是 CPU 和 GPU 共同合作完成的,其中 CPU 负责把 UI 组件计算成 Polygons,Texture 纹理,然后交给 GPU 进行栅格化渲染。如果在主线程做了耗时的操作,简单的会造成界面的卡顿,严重的直接ANR。

各界面耗时操作ANR时间对比:

  • 主线程:5秒
  • 广播接收者:10秒
  • 服务:20s

频繁GC

如果频繁创建大对象或者频繁创建大量对象,并且这些对象属于用完就废弃的,这可能会导致内存抖动的问题。

  • 大对象可以使用对象池复用,比如 byte[]
  • 尽量在 16ms 内少创建对象,比如不要在 onDraw 中创建 Paint 对象,decodeBitmap 之类的

其他优化

  • 如果是一些简单的图片,使用ShapeDrawable
  • 如果是可拉伸的图片背景,使用draw9patch

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :