为了账号安全,请及时绑定邮箱和手机立即绑定

【学习打卡】第5天 App 布局优化

标签:
Android

课程名称:Top团队大牛带你玩转Android性能分析与优化
课程章节:App性能概览与平台化实践
主讲老师:随风绽放

课程内容

1.Android 绘制原理及工具选择

在计算机硬件中,通常 CPU 用来处理数据,GPU 用来渲染数据,Android 系统也不例外,绘制过程首先是 CPU 准备数据,通过 Driver 层把数据交给 GPU 渲染,其中 CPU 主要负责 Measure、Layout、Record、Execute 的数据计算工作,GPU 负责 Rasterization(栅格化)、渲染。

无论是 CPU 准备的数据,还是 GPU 要渲染的数据,都是一帧一帧的形式。我们看到的界面也是由一帧一帧的图像连续显示而来。对于人眼来说,每秒看到 60 帧是比较流畅的,即 FPS(Frame Per Second)为 60,1/60 = 0.0167,即每 16 ms进行一次准备、渲染工作。

常用的布局优化工具有以下几种:

    1. Systrace,内存优化工具中也用到了 Systrace,这里关注 Systrace 中的 Frames 页面,正常情况下圆点为绿色,当出现黄色或者红色的圆点时,表现出现了丢帧。
    1. Layout Inspector,是 AndroidStudio 自带工具,可以查看页面的视图层次结构。
    1. Choreographer,是 Android16 加入的一个工具类,通过 Choreographer.getInstance().postFrameCallback,可以实时获取 FPS。

Android 的布局加载时 IO 操作,比如 xml 文件要通过 xml 解析器才能加载到内存里。在加载 xml 文件的时候,还会用到反射,而反射本来性能就不高。

2.优雅获取界面布局耗时

在对布局优化前,我们需要找到一个指标,作为衡量布局优化效果的标准。常用有下面几种方式来获取页面加载的耗时。

  1. 常规方式,通过手动埋点的方式来确认页面加载的耗时,这种方式代码侵入性强,工作量大,不便于后期的维护。
  2. AOP 方式,通过对 Activity 的 setContentView()方法切片,获取加载每个页面的耗时,这种方式代码侵入性小。

通过上面的方式可以获取页面加载的耗时,为了更加精细化的优化,如何获取每个控件加载的耗时呢? 可以通过 LayoutInflater.Factory(考虑兼容性可以使用 LayoutInflaterCompat.setFactory2) 来实现,这种方式代码侵入性小。通过自定义 Factory,在 onCreateView() 方法的中实现对每个控件加载耗时的计算。使用时需要注意,这个设置应该在super.onCreate()之前,否则无效。

public interface Factory {
        /**
         * Hook you can supply that is called when inflating from a LayoutInflater.
         * You can use this to customize the tag names available in your XML
         * layout files.
         *
         * <p>
         * Note that it is good practice to prefix these custom names with your
         * package (i.e., com.coolcompany.apps) to avoid conflicts with system
         * names.
         *
         * @param name Tag name to be inflated.
         * @param context The context the view is being created in.
         * @param attrs Inflation attributes as specified in XML file.
         *
         * @return View Newly created view. Return null for the default
         *         behavior.
         */
        public View onCreateView(String name, Context context, AttributeSet attrs);
    }

3.异步 Inflate

前面介绍到布局文件加载的过程是一个 IO 过程,创建对象时还使用到反射,使用反射创建对象的速度比通过 new 关键字创建要慢 3 倍左右。所以布局优化的方向是尽量减少 IO 过程,减少通过反射来创建对象。

这里介绍一种侧面优化布局的方式即异步实现布局的加载。AsyncLayoutInflater 是一个异步初始化布局的 Helper 类。它的本质就是把对布局文件的 inflate 放入到了子线程里面,等到初始化成功后,在通过接口抛回到主线程。

4.布局加载优化

有没有一种方法从根本上来解决io操作慢、反射慢的问题呢?答案是直接用 Java 代码写布局文件,这样会引入新问题,不便于开发、可维护性差。用 xml 来写布局,虽然IO慢、反射慢,因为方便维护,可读性好,还方便写UI时进行预览。那有没有一个方案既能保留XML优点,还能解决其性能问题呢?X2C 就是这样一个方案。

X2C 的原理是在 APT 编译期将需要翻译的布局 xml 文件翻译生成对应的 java 文件,这样对于开发人员来说写布局还是写原来的 xml ,但对于程序来说,运行时加载的是对应的 java 文件

不论是异步加载 AsyncLayoutInflater,还是 X2C 方案,都要考虑下面的问题:

    1. 控件的一部分属性在 xml 文件中使用是可以的,在 Java 代码中是不支持的,这部分属性虽然很少,但还是存在,使用的时候需要注意。
    1. 另外一个问题是失去了系统的兼容性,无法使用 AppCompat 等兼容类,无法做到控件的向下兼容。这时就要考虑对两种方案进行定制,来获得兼容性。

5.视图绘制优化实战

前面对布局优化的方案都是针对布局加载进行优化的,这里介绍一下在视图绘制时的优化方案。Android 中的视图绘制要经历三个过程:

  1. 测量,在测量阶段确定视图的大小;
  2. 布局,在布局阶段确定视图的位置;
  3. 绘制,在绘制阶段完成视图的绘制。

三个过程的实现都会涉及 View 树自顶向下的遍历,有时甚至还会触发多次,所以每个阶段都会出现耗时的情况,都是我们去优化的方向。布局优化在绘制阶段的准则是尽量减少 View 树的层级,页面布局要做到宽而浅、避免窄而深

ConstraintLayout 是在 Android Studio 2.2 中主要的新增功能之一,它可以有效地解决布局嵌套过多的问题,实现几乎完全扁平化布局,构建复杂布局的性能更高,它有点类似于RelativeLayout,但远比RelativeLayout要更强大。除了使用 ConstraintLayout,还可以考虑以下的优化方式:

  1. 不嵌套使用 RelativeLayout;
  2. 不在嵌套的 LinearLayout 中使用 weight 属性;
  3. 使用 merge 标签,可以减少一个 view 层级,但是只能用在根 View 中;

过度绘制就是在同一个区域中叠加了多个控件,重复的叠加就是过度绘制,很可能会造成刷新率下降,造成卡顿的现象。对于过度绘制的测试主要通过人工进行测试,也是发现应用过渡绘制的首选途径,通过打开开发者选项中的 显示GPU过度绘制。过渡绘制可以通过颜色标识,按照从好到差依次是:蓝、绿、淡红、红。

  1. 蓝色1x过度绘制
  2. 绿色2x过度绘制
  3. 淡红色3x过度绘制
  4. 红色超过4x过度绘制

避免过度绘制的方法:

  1. 去掉多余背景色,减少复杂shape使用;
  2. 避免层级叠加;
  3. 自定义 View 使用 clipRect 屏蔽被遮盖View绘制;

布局优化的其它技巧:

  1. 使用 ViewStub 标签来加载一些不常用的布局,ViewStub 是一个高效的占位符可以实现延迟初始化。
  2. 在 onDraw() 方法中避免创建大对象和其它耗时操作
  3. TextView 的优化,TextView中很多操作都很繁重。比如setText操作,须要设置SpanWatcher,或者要重现创建一个 SpannableString,还要依据情况又一次创建TextLayout,这些操作加起来之后令一次 setText 操作很耗时。可以通过自定义 view 的方式来优化,对于可编辑的文本,使用 DynamicLayout 来实现,对于静态文本,推荐使用StaticLayout。

课程收获

课程从布局加载、布局绘制的角度介绍了布局优化的方案,涵盖了布局优化的所有手段。既提供了获取优化指标的方式,又提供了优化的手段,非常实用。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
11
获赞与收藏
16

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消