Android XML布局文件优化

Android中XML布局文件的使用非常频繁,在加载XML布局的时候,如果对XML文件其进行优化,将会提高加载的效率,为我们带来更好的体验。我在这里对一些常见的优化方法进行一下小结,以作为记录。

1.扁平化布局

在Android加载XML布局文件,创建View或者ViewGroup的时候,XML文件的布局的深度和广度都会对这个过程造成影响,具体请参考

 http://lishoubo.github.io/2013/08/12/android-measure-procedure/   android measure procedure  ,这篇博客对该过程作了详细的解读。因此XML文件布局的深度和广度都会使创建View的过程更加的耗时,尤其是在布局文件多层嵌套的情况下,因此我们在进行布局的时候,应该尽量考虑使用扁平化的结构,减少布局的深度和复杂性。

常见情况下我们会使用LinearLayout和RelativeLayout以及FrameLayout,在Android 4.0以后,系统默认使用RelativeLayout作为布局文件的顶层节点,因为其能更准确的获知其中View的位置和大小,相对而言,LinearLayout则需要多次进行测量布局操作,才能获取到正确的信息。RelativeLayout可以更加方便地实现一些LinearLayout需要进行嵌套才能实现的一些布局,这样对于实现布局的扁平化有更好的效果。

例如要实现下面的布局效果

Android XML布局文件优化_第1张图片


使用LinearLayout的代码如下:



使用RelativeLayout的代码如下:



通过比较可以看出,使用RelativeLayout的情况下,可以减少一个LinearLayout的使用,使得所有的ImageView控件都处于同一个层级,降低了布局结构的深度,在使用该布局创建View的时候,可以提高效率。这种情况是一种很常见的情形,也非常的简单,我们随手就可以做到。坚持这种做法,并在更复杂的布局中使用这一原则,一定会收到更好的效果。

同样,我们可以减少布局中不必要的控件的使用,以达到精简布局的效果。例如通过为TextView设置图片,来替换ImageView与TextView的组合,实现同样的效果,而这样只使用了一个控件。还有其他一些小技巧,例如使用HTML标签优化TextView显示,可以参考 http://blog.csdn.net/ljtyzhr/article/details/42402043

2.include标签的使用

在应用的多个界面中,经常会有几个界面存在相同或者类似的部分,例如标题栏,导航栏之类的。这些重复的界面如果一一写下来,既浪费时间精力,又不方便统一管理,例如需要改动的时候,在这种情况下,可以把这个重复的界面布局独立出来,然后通过include标签,将这个布局导入需要引用的地方,这样就可以只维护这个独立出来的布局文件即可。

假设这是一个可供复用的独立布局文件,文件名为titlebar.xml

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

    <ImageView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:src="@drawable/gafricalogo" />
FrameLayout>
然后你就可以在需要引入这部分布局的文件中,通过include标签,导入这部分布局。
<include layout="@layout/titlebar"/>

<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>
然后titlebar.xml中的布局就替换了include标签位置的部分。

在使用include标签的时候需要注意:

可以复写所有layout属性(任何android:layout_*属性),但是必须同时复写layout_width和 layout_height属性,这些复写的layout属性才会生效。例如:

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

你也可以在include标签中给这个布局定义一个id,这样将会覆盖其独立布局文件中的id值。在声明独立布局中的子View的时候,需要先

FrameLayout titleView  =  findViewById(R.id.new_title);

然后再在titleView中使用  titleView.findViewById() 方法,直接使用findViewById将无法找到其中的子View。


3.merge标签的使用

merge标签可以用来代替布局文件中的根节点,例如LinearLayout,RelativeLayout,FrameLayout等元素。配合include标签,可以减少布局的嵌套。例如

<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标签将以上布局复用的时候,将会直接把两个Button放在include标签的位置,而不会再使用其他容器来包装这两个Button,这样就会减少不必要的嵌套,有利于布局的扁平化。


4.ViewStub使用

在实际应用中,可能存在一部分界面是处于隐藏状态的,在一定的条件下,才会展示出来。我们一般会将这部分节目使用setVisibility(View.GONE)方法将其隐藏起来,但是我们更推荐使用ViewStub来达到相同的目的。因为ViewStub是一个处于不可见状态的View,初始状态时不会被加载出来,不会浪费资源,而处于View.GONE状态的View也是需要被加载的。ViewStub的使用方法类似include标签,需要在其中声明需要加载的布局文件

  my_comment_layout布局如下: 
  

  
  

在需要加载这部分布局的时候,可以通过两种方式实现加载:

通过setVisibility(View.VISIBLE)的方式,这时候可以通过判断其可见性来得知其是否已经加载  

// 方式1,获取ViewStub,  
        ViewStub listStub = (ViewStub) findViewById(R.id.stub_import);  
        // 加载评论列表布局  
        listStub.setVisibility(View.VISIBLE);  
        // 获取到评论ListView,注意这里是通过ViewStub的inflatedId来获取  
            ListView commLv = findViewById(R.id.stub_comm_lv);  
                if ( listStub.getVisibility() == View.VISIBLE ) {  
                       // 已经加载, 否则还没有加载  
                }  
            } 

通过inflate方法来实现加载。注意此时无法通过判断可见性来判断是否已经加载了,可以通过判断其中的元素是否存在来判断加载情况。

 // 把commLv2设置为类的成员变量  
    ListView commLv2 = null;  
    //  
    public void onCreate(Bundle b){  
        // main.xml中包含上面的ViewStub  
        setContentView(R.layout.main);  

        // 方式二  
        ViewStub listStub2 = (ViewStub) findViewById(R.id.stub_import) ;  
        // 成员变量commLv2为空则代表未加载  
        if ( commLv2 == null ) {  
        // 加载评论列表布局, 并且获取评论ListView,inflate函数直接返回ListView对象  
          commLv2 = (ListView)listStub2.inflate();  
        } else {  
        // ViewStub已经加载  
        }  

    } 
需要注意的是,如果ViewStub设置了inflatedId,那么将需要通过该id来查找布局的根元素。

详细讲解请阅读 http://www.codeceo.com/article/android-viewstub-include-merge.html


5.hierarchy viewer工具的使用


6.其他优化

参考:

http://www.codeceo.com/article/android-viewstub-include-merge.html

未完待续

你可能感兴趣的:(Android)