Android 性能优化——布局优化(include 标签、merge 标签和 ViewStub)

    一个应用使用起来是否流畅对于用户来说是首要体验感,因为对于非开发者的用户来说,很难理解到 Android 中一个功能实现的难易程度,他们能判断这个应用是否好用的依据可能就是在功能实现上、动画上、流畅度上等。其中流畅度基本上是最重要的,当用户使用一个软件,如果页面加载很慢,或者经常发生 OOM 导致异常退出,那么这个应用一定不会收用户喜爱,所以对于 Android 应用的优化是非常重要的。

    其中页面优化便是其中之一,如果你的布局文件嵌套太多,Android 绘制时必然要花费更多的时间。这个不太了解的可以看看Android View 的工作原理

    进行布局优化时,除了可以删除无用的控件和层级之外,还要学会选择总性能最高的 ViewGroup。在 Android 中,RelativeLayout 的性能较低 ,如果当一个布局能够使用 RelativeLayout 实现,也可以使用 LinearLayout 实现时,优先选择 LinearLayout。但是当一个布局需要使用 多个 LinearLayout 或者 多个 FrameLayout 来嵌套实现时,可能相对来说使用不嵌套的 RelativeLayout 能够实现的话性能会更高效。

    布局优化还可以使用 <include> 和 <merge> 标签和 ViewStub。

  • <include>标签

    <include>标签可以将一个指定的布局添加到当前布局文件中,比如我们先建立一个 layout_button.xml:


然后我们新建一个 layout_test.xml,使用<include>标签,将 layout_button.xml 插入进去:


    <include>标签的好处就是,当使用 layout="" 属性指定了一个布局文件,就可以不用重复再写一遍这个布局的内容了。但是需要注意的是,<include> 标签只支持以 layout_ 开头的属性。而且当布局文件和<include>标签都指定了 id 属性,以<include>标签为主。

  • <merge>标签

    <merge>标签一般是用来和<include>标签搭配使用减少嵌套的,当<include>标签的父标签布局属性是啥,<merge>标签的布局属性就是啥,比如<include>标签的父标签是一个按 vertical 排列的 LinearLayout,那么<merge>标签内各控件就是默认按 vertical 排列的 LinearLayout 排列,比如<include>标签的父标签是一个按 horizontal 排列的 LinearLayout,那么<merge>标签内各控件就是默认按 horizontal 排列的 LinearLayout 排列。

   先新建一个 layout_merge.xml 的布局:

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

    <Button
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="Button"/>
    <Button
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="Button"/>
</merge>

    如果<include>标签的父标签是一个按 vertical 排列的 LinearLayout,那么布局结果如下:


    如果<include>标签的父标签是一个按 horizontal 排列的 LinearLayout(当然为了保证<merge>标签内元素能够横向排列,我们得先把两个 Button 的 layout_width="" 属性修改一下):

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

    <Button
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="Button"/>
    <Button
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="Button"/>
</merge>

    结果如下:

     当然,如果<include>标签的父标签是一个 RelativeLayout,<merge>内元素排列便是按照 RelativeLayout,其它布局类型也一样。

  • ViewStub

    ViewStub 继承自 View,非常轻量级且高宽都是0,这个可以通过 ViewStub 的 onMeasure() 方法得知:


    ViewStub 的作用是可以按照需求来加载显示需要的布局文件,比如在网络异常或者注册时信息过多时,完全不需要一下子加载所以布局,就可以使用 ViewStub 来需要时再加载布局,提高程序的性能。

    比如我们先建立两个布局文件:layout_text_a.xml 和 layout_text_b.xml:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tv_a"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Im Text A"
    android:gravity="center_horizontal"
    android:textSize="24sp"/>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tv_b"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Im Text B"
    android:gravity="center_horizontal"
    android:textSize="24sp"/>

    然后我们去 layout_main.xml 中去添加两个 <ViewStub>:

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

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="按钮1"
        android:onClick="showAText"/>
    <ViewStub
        android:id="@+id/viewstub_a"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout="@layout/layout_text_a"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="按钮1"
        android:onClick="showBText"/>
    <ViewStub
        android:id="@+id/viewstub_b"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout="@layout/layout_text_b"/>
</LinearLayout>

    <ViewStub>标签内的 layout 属性是用来放要按需加载的布局的,我们给两个按钮分别添加点击事件 showAText 和 showBText 用来显示我们的 ViewStub。

    接下来是 MainActivity.java 的代码:

public class MainActivity extends AppCompatActivity {
    private ViewStub viewStubA;
    private ViewStub viewStubB;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewStubA = (ViewStub) findViewById(R.id.viewstub_a);
        viewStubB = (ViewStub) findViewById(R.id.viewstub_b);
    }
    //按钮1的点击事件,展现 Text A
    public void showAText(View view){
        //使用 inflate() 方法显示 Text A
        try {
            viewStubA.inflate();
        }catch (Exception e){
            Log.e("Error","只能 inflate 一次");
        }
    }
    //按钮1的点击事件,展现 Text B
    public void showBText(View view){
        //使用 detVisibility() 显示 Text B
        viewStubB.setVisibility(View.VISIBLE);
    }
}

    展现 ViewStub 有如上两种方法,但是需要注意的是 ViewStub 只能 inflate() 一次,如果两次便会出现错误导致程序异常退出,所以我们要抛出异常。

    下面是效果图:


    电脑上没有 gif 图录制工具,大家将就看一下,大致就是这个流程。

    

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值