(两百五十三) 学习改善布局性能

学习https://developer.android.google.cn/training/improving-layouts/optimizing-layout

 

优化布局层次结构

使用基本布局结构可打造最高效的布局是一种常见的误解。无论如何,您添加到应用中的每个微件和布局都需要进行初始化、布局和绘制。例如,使用 LinearLayout 的嵌套实例会导致视图层次结构过深。此外,嵌套多个使用 layout_weight 参数的 LinearLayout 实例成本非常高,因为每个子级都需要测量两次。如果要反复扩充布局(例如,在 ListViewGridView 中使用时),则要特别注意这方面。

 

检查布局

Android SDK 工具包含一个名为 Hierarchy Viewer 的工具,可让您在应用运行时分析布局。使用此工具可帮助您发现布局性能方面的瓶颈。

通过 Hierarchy Viewer,您可以在已连接的设备或模拟器上选择正在运行的进程,然后显示布局树。各个块上的信号灯代表其测量、布局和绘制性能,有助于您识别潜在问题。

例如,图 1 显示了用作 ListView 中的一项的布局。此布局左侧显示了一张小小的位图,而右侧则显示了两个堆叠的文本项。尤其重要的是,将多次扩充的布局(例如此布局)已经过优化,因为性能优势将会成倍地提升。

图 1. ListView 中的一项的概念性布局。

Hierarchy Viewer 会显示可用设备及其正在运行的组件的列表。从 Windows 标签中选择您的组件,然后点击 Hierarchy View 查看所选组件的布局层次结构。例如,图 2 显示了图 1 所示列表项的布局。

图 2. 图 1 中的布局的布局层次结构,使用 LinearLayout 的嵌套实例。

修改布局

由于上述布局性能因嵌套的 LinearLayout 而有所下降,因此可以通过展平布局(使布局变浅变宽,而非变窄变深)来提高性能。作为根节点的 RelativeLayout 允许此类布局。因此,将此设计转换为使用 RelativeLayout 后,该布局便会成为 2 级层次结构。检查新布局是否如下所示:

图 4. 图 1 中的布局的布局层次结构,使用 RelativeLayout

这些优势可能看起来并不显眼,但却会成倍地提升性能,因为此布局用于列表中的每一项。

大部分差异都是由于在 LinearLayout 设计中使用 layout_weight 造成的,这会减缓测量速度。这只是如何恰当地使用每个布局的其中一个示例,您应仔细考虑是否有必要使用布局权重。

简而言之就是布局要尽量扁平化,尽量简单,去除冗余布局

 

通过 重复使用布局

尽管 Android 通过各种微件来提供可重复使用的小型互动元素,但您可能还需要重复使用需要特殊布局的大型组件。为了高效地重复使用完整的布局,您可以使用 <include/><merge/> 标记在当前布局中嵌入其他布局。

重复使用布局特别强大,因为它允许您创建可重复使用的复杂布局。例如,“是/否”按钮面板,或包含说明文本的自定义进度条。这也意味着您可以单独提取、管理多个布局中的任何常见应用元素,然后将其添加到各个布局中。因此,尽管您可以通过编写自定义 View 来创建单独的界面组件,但也可以通过重复使用布局文件来更加轻松地完成该操作。

创建可重复使用的布局

如果您已经知道您想要重复使用的布局,请创建一个新的 XML 文件并定义布局。例如,下面的布局定义了要添加到每个 Activity 中的标题栏 (titlebar.xml):

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/titlebar_bg"
        tools:showIn="@layout/activity_main" >

        <ImageView android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:src="@drawable/gafricalogo" />
    </FrameLayout>
    

View 应该与您希望在添加此布局的每个布局中显示的方式完全一致。

注意:上述 XML 中的 tools:showIn 属性是一个特殊属性,系统会在编译过程中将其移除,并且仅在设计时在 Android Studio 中使用它 - 它指定了包含此文件的布局,因此,您可以在它出现并嵌入到其父级布局中时预览(和修改)此文件。

使用 <include> 标记

在要添加可重复使用的组件的布局中,添加 <include/> 标记。例如,下面的布局包含上述标题栏:

下面是布局文件:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/app_bg"
        android:gravity="center_horizontal">

        <include layout="@layout/titlebar"/>

        <TextView android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:text="@string/hello"
                  android:padding="10dp" />

        ...

    </LinearLayout>
    

您还可以通过在 <include/> 标记中指定已添加布局的根视图的所有布局参数(任何 android:layout_* 属性)来替换它们。例如:

    <include android:id="@+id/news_title"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             layout="@layout/title"/>
    

不过,如果您想要使用 <include> 标记替换布局属性,则必须同时替换 android:layout_heightandroid:layout_width,其他布局属性才能生效。

使用 <merge> 标记

在一个布局中包含另一个布局时,<merge /> 标记有助于消除视图层次结构中的冗余视图组。例如,如果您的主布局是一个垂直 LinearLayout,其中两个连续视图可以在多个布局中重复使用,那么放置这两个视图的可重复使用布局需要有自己的根视图。不过,如果使用另一个 LinearLayout 作为可重复使用的布局的根,则会导致垂直 LinearLayout 内出现垂直 LinearLayout。嵌套的 LinearLayout 除了会降低界面的性能之外,没有任何实际用途。

为了避免包含此类冗余视图组,您可以改用 <merge> 元素作为可重复使用的布局的根视图。例如:

    <merge xmlns:android="http://schemas.android.com/apk/res/android">

        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/add"/>

        <Button
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/delete"/>

    </merge>
    

现在,当您将该布局添加到其他布局中(使用 <include/> 标记)时,系统会忽略 <merge> 元素并直接在布局中放置两个按钮,以代替 <include/> 标记。

 

视图加载延迟

有时,您的布局可能需要很少使用的复杂视图。无论是作品详情、进度指示器还是撤消消息,您都可以通过仅在需要时加载这些视图来减少内存使用量并加快渲染速度。

如果您具有应用将来可能需要的复杂视图,则可以使用延迟加载资源这项重要的方法。您可以通过为复杂且很少使用的视图定义 ViewStub 来实现该方法。

定义 ViewStub

ViewStub 是一种没有任何维度的轻量型视图,它不会绘制任何内容或参与布局。因此,扩充和离开视图层次结构的成本比较低。每个 ViewStub 只需包含 android:layout 属性即可指定要扩充的布局。

以下 ViewStub 适用于半透明进度条叠加层,只有当新的项导入应用中时,它才会显示。

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

加载 ViewStub 布局

当您想要加载 ViewStub 指定的布局时,可通过调用 setVisibility(View.VISIBLE) 将其设为可见,或调用 inflate()

KotlinJava

    findViewById(R.id.stub_import).setVisibility(View.VISIBLE);
    // or
    View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
    

注意inflate() 方法会在完成后返回扩充的 View。因此,如果您需要与布局互动,则无需调用 findViewById()

该布局可见/扩充之后,ViewStub 元素将不再是视图层次结构的一部分。它会被替换为经过扩充的布局,该布局的根视图的 ID 便是由 ViewStub 的 android:inflatedId 属性指定的那个 ID。(为 ViewStub 指定的 ID android:id 仅在 ViewStub 布局可见/扩充之前有效。)

注意ViewStub 的一个缺点是它目前不支持要扩充的布局中的 <merge> 标记。

 

总结

改善布局性能可以有如下方法

(在层次结构的所有叶节点(最低叶节点除外)中避免使用 RelativeLayout,或避免使用 LinearLayout 的权重功能)

  • 使用include和merge
  • 使用ViewStub懒加载

 

 

 

 

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 鲸 设计师: meimeiellie
应支付0元
点击重新获取
扫码支付

支付成功即可阅读