性能调优UI篇(一)——ViewStub

在项目中,我们忙于赶着功能的实现,整个app的性能很差。每个页面加载都卡到不行。暑假马上就要到了,项目组专门安排了一个提升性能的版本。版本还没开始做,我提前在这里记录一下性能调优的一些方法和尝试。

今天学习并尝试的是ViewStub。在app的UI中,我们时常会有一些View是“隐形的”即,我会在xml中给它设置将它的visibility设为gone。只有在特殊情况下,我才会将它显现出来。比如悬浮的Button会在我滑动内容时消失,部分按钮只有有权限的用户才看见等等情况。用View设置visibility的方式,最大的好处就是灵活。我可以动态地在程序中,根据一些条件判断,随时显现或者隐藏这些控件,使整个交互充满灵动。

但除了以上情况,还有另一种情况。比如,在列表为空时,我会加载一幅特殊的画,用以提示用户列表没有内容,或者在用户第一次登录时会显示每个按钮,之后就不会再看到了。这些情况归纳起来就是,这些控件大部分情况下处于隐形状态。只有少数情况它需要被显示出来。我如果依然把它写在xml里面,只是设置一下visibility = gone,显得非常不划算。因为不论visibility设置成什么,系统都已经把它加载出来了,加载的时间已经花了,内存也占用了,我却有很大的可能根本不会使用它。因此,我们可以使用ViewStub。ViewStub是一个轻量级的view,我们只有一次给它绘制的机会。它在不绘制时,占用的内存是非常小的,且加载时间也很短。当我们需要它时,我们再绘制它,整体花的时间与View的直接加载相差不大。所以,如果这个View显示的机会不多,我们更推荐使用ViewStub进行显示。

代码如下:

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1">

        <Button
            android:id="@+id/test_btn2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerInParent="true"
            android:text="test2"
            android:onClick="testclick2"/>
        <ViewStub
            android:id="@+id/test_view2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:inflatedId="@+id/test_image_view"
            android:layout_above="@id/test_btn2"
            android:layout="@layout/test_image_view"
            />
    </RelativeLayout>
</LinearLayout>

test_image_view.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/test_img_src"
        />

</LinearLayout>

MainActivity.java:

package com.dream.fishbonelsy.viewstubdemo;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewStub;
import android.widget.ImageView;
import android.widget.Toast;


public class MainActivity extends ActionBarActivity {
private ViewStub view2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        long startTime = System.nanoTime();  //开始时间        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        view2 = (ViewStub) findViewById(R.id.test_view2);
        long consumingTime = System.nanoTime() - startTime; //消耗时间
        Log.d("tag" , "布局时间:"+ consumingTime/1000000+"毫秒");
    }

    public void testclick2(View view){
        long startTime = System.nanoTime();  //开始时间
        view2.inflate();
        long consumingTime = System.nanoTime() - startTime; //消耗时间
        Log.d("tag" , "绘制时间:"+consumingTime/1000000+"毫秒");
    }
}

 消耗时间如图:

相同的内容我经过了多次测试,发现ViewStub的布局时间非常短,之后加载也不会太慢。对于同样的内容,我采用了ImageView设置visibility尝试了一次。

代码如下:

activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1">

        <Button
            android:id="@+id/test_btn1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerInParent="true"
            android:text="test1"
            android:onClick="testclick1"/>
        <ImageView
            android:id="@+id/test_view1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/test_img_src"
            android:visibility="gone"
            android:layout_above="@id/test_btn1"
            />
    </RelativeLayout>
</LinearLayout>

MainActivity.java:

package com.dream.fishbonelsy.viewstubdemo;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewStub;
import android.widget.ImageView;
import android.widget.Toast;


public class MainActivity extends ActionBarActivity {

    private ImageView view1;
    private ViewStub view2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        long startTime = System.nanoTime();  //開始時間
//
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        view1 = (ImageView) findViewById(R.id.test_view1);
        //view2 = (ViewStub) findViewById(R.id.test_view2);
        long consumingTime = System.nanoTime() - startTime; //消耗時間
        Log.d("tag" , "布局时间:"+ consumingTime/1000000+"毫秒");
    }

    public void testclick1(View view){
        long startTime = System.nanoTime();  //開始時間
        view1.setVisibility(View.VISIBLE);

        long consumingTime = System.nanoTime() - startTime; //消耗時間
        Log.d("tag", "绘制时间:" + consumingTime / 1000 + "微秒");
    }
}

消耗时间如图:

分析上面两份时间数据我们可以观察出这样的结果:

一、两种方案在要显示这个图时,所花的时间是相当的。此时用View更好,因为View更灵活,我可以反反复复地隐藏和显现,可以设置点击事件,甚至可以重绘等等。

二、两种方案在不显示这张图时,ViewStub的加载时间会大大降低,同样的,消耗内存也会少很多。

因此,可以暂时总结为:当我需要一个灵活的控件,它需要变化、监听、隐藏、移动时,我应该选择View。由于,ViewStub只能绘制一次,不能监听,不能重绘,不能移动,不能隐藏,所以当我需要一个不常显示的备用View时,使用ViewStub可以大大节省我们的系统资源。(比如,当列表内容为空,显示某图;当网络情况不好,显示某图;当用户第一次登录,显示某图)。我们需要预估这个View出现的频率,来最终决定方案。

暂时Done。

发现性能优化真是需要丰富的经验,然后一点点扣出来的性能。学海无涯啊~

原文地址:https://www.cnblogs.com/fishbone-lsy/p/4565026.html