天天看点

Android 性能优化之布局优化

快(流畅的体验)

稳(稳定)

省(省电/流量)

小(安装包小)

这四点很形象的代表了性能的四个方面,同时也让我们知道我们 App 现在是否是款性能良好的 APP,如果有一项不达标,那么说明我们的应用有待优化。

过度绘制

定义

过度绘制(Overdraw):指的是屏幕上的某个像素在同一帧的时间内被绘制了多次。

检测

Android手机上面的开发者选项提供了工具来检测过度绘制,可以按如下步骤来打开:

开发者选项->调试GPU过度绘制->显示过度绘制区域

Android 性能优化之布局优化

注意:

有些过度绘制是无法避免的。因此在优化界面时,应该尽量让大部分的界面显示为真彩色(即无过度绘制)或者为蓝色(仅有 1 次过度绘制)。尽量避免出现粉色或者红色。

优化

1. 移除布局中不需要的背景

  • 移除 Window 默认的 Background

    方式一:在theme中设置

<style name="AppTheme" parent="主题">
        <item name="android:windowBackground">@null</item>
    </style>
           

方式二:在Activity的onCreate()方法中添加:

  • 移除控件中不需要的背景

2. 将layout层级扁平化

  • Layout Inspector来查看layout的层次结构。

    在Android Studio中点击 Tools > Android > Layout Inspector。然后在出现的 Choose Process 对话框中,选择想要检查的应用进程即可。

    Layout Inspector会自动捕获快照,然后会显示以下内容:

    • View Tree:视图在布局中的层次结构。
    • Screenshot:每个视图可视边界的设备屏幕截图。
    • Properties Table:选定视图的布局属性。
      Android 性能优化之布局优化
    • 使用嵌套少的布局

      我们可以使用 LinearLayout 和 RelativeLayout 来完成。但是 LinearLayout 相比于 RelativeLayout,就多了一层,所以 RelativeLayout 明显是一个更优的选择。

    • 使用 include 标签能够复用布局

      可以将一个指定的布局文件加载到当前的布局文件中。如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <include layout="@layout/title_bar"/>
    
    <TextView
        android:id="@+id/first_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/rect_color_primary"
        android:gravity="center"
        android:padding="@dimen/item_spacing"
        android:text="FirstExample"
        android:textColor="@color/colorPrimaryDark"/>

    ...
</LinearLayout>
           

需要注意的是,如果include标签指定了layout_*这种属性,那么要求

android:layout_width和android:layout_height必须存在,否则其他的android:layout_*形式的属性无法生效。

- 使用 merge 标签减少嵌套
一般和include标签一起使用从而减少布局的层级。在上述示例中,由于当前布局是一个竖直方向的LinearLayout,用过merge标签就可以去掉多余的那一层LinearLayout。如下:
           
<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button1"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="button2"/>
</merge>
           

ViewStub

ViewStub继承了View,它非常轻量级且宽和高都是0,因此它本身不参与任何的布局和绘制过程。比如:网络异常时的界面,这个时候就没有必要在整个界面初始化将其加进来,通过ViewStub就可以做到在使用的时候再加载,提高了程序初始化的性能:

<ViewStub
       android:id="@+id/stub_import"
       android:inflatedId="@+id/panel_import"
       android:layout="@layout/layout_empty_txt"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" 
       android:layout_gravity="bottom"/>
           

panel_import是@layout/layout_empty_txt这个布局的根元素的id。

在需要加载ViewStub中的布局时,可以按照如下两种方式:

或者

通过上述两个方法加载后,ViewStub就会被它内部的布局替换掉,这个时候ViewStub就不再是整个布局结构中的一部分了。

  • 使用lint来优化布局的层次结构

    lint是一个静态代码分析工具,可以用来协助优化布局的性能。要使用lint,点击Analyze> Inspect Code即可。

布局性能方面的信息位于Android> Lint> Performance下,我们可以点开它来看下一些优化建议。

下面是lint的一些优化技巧:

  • 使用复合图片

    如果一个线性布局中包含一个 ImageView 和一个 TextView,可以使用复合图片来替换掉

  • 合并根节点

    如果一个FrameLayout 是整个布局的根节点,并且也没有提供背景、留白等等,那么可以使用标签来替换掉,因为DecorView本身就是一个FrameLayout。

  • 移除布局中无用的叶子

    布局是一个树形的结构,如果一个布局没有子 View 或者背景,那么可以把它移除掉(这布局本身就不可见了)。

  • 移除无用的父布局

    如果一个布局没有兄弟,也不是ScrollView 或者根 View,并且也没有背景,那么可以把这个父布局移除掉,然后把它的子view移到它的父布局下。

  • 避免过深的层次结构

    过多的布局嵌套不利于性能,可以使用更扁平化的布局,如RelativeLayout、GridLayout、ConstraintLayout等布局来提高性能。布局默认的最大深度为10。

布局优化技巧

  • 使用性能更优的布局

    推荐使用 ConstraintLayout

  • 使用include标签提高布局的复用性
  • 使用ViewStub标签延迟加载
  • onDraw()中不要创建新的局部变量以及不要做耗时操作
  • 使用GPU呈现模式分析工具来分析渲染速度

    点击开发者模式->监控->GPU呈现模式,然后选择 在屏幕上显示为条形图 即可以看到一个图表。

    Android 性能优化之布局优化

优质文章:

  • Android 性能优化最佳实践

继续阅读