【Android 开发技巧】布局优化利器<include/>和ViewStub

标签: android 开发 技巧 | 发表时间:2014-09-04 08:24 | 作者:manoel
出处:http://blog.csdn.net

『原创作品,转载请注明出处。 --- 孙国威』

〔文章原始地址  http://blog.csdn.net/manoel/article/details/39036507


当创建复杂的布局的时候,有时候会发现添加了很多的ViewGroup和View。随之而来的问题是View树的层次越来越深,应用也变的越来越慢,因为UI渲染是非常耗时的。

这时候就应该进行布局优化了。这里介绍两种方式,分别为<include>标签和ViewStub类。


<include/>

使用<include/>是为了避免代码的重复。设想一种情况,我们需要为app中的每个视图都添加一个footer,这个footer是一个显示app名字的TextView。通常多个Activity对应多个XML布局文件,难道要把这个TextView复制到每个XML中吗?如果TextView需要做修改,那么每个XML布局文件都要进行修改,那简直是噩梦。

面向对象编程的其中一个思想就是代码的复用,那么怎么进行布局的复用呢?这时,<include/>就起作用了。

如果学过C语言,那么对#include应该不陌生,它是一个预编译指令,在程序编译成二进制文件之前,会把#include的内容拷贝到#include的位置。

Android中的<include/>也可以这么理解,就是把某些通用的xml代码拷贝到<include/>所在的地方。以一个Activity为例。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:text="@string/hello" />
    
    <include layout="@layout/footer_with_layout_properties"/>


</RelativeLayout>
footer_with_layout_properties.xml中就是一个简单的TextView,代码如下:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_marginBottom="30dp"
    android:gravity="center_horizontal"
    android:text="@string/footer_text" />
上述的代码中,我们使用了<include/>标签,达到了代码复用的目的。

但是,仍然存在一些疑惑。

footer_with_layout_properties.xml中使用了android:layout_alignParentBottom属性,这个属性之所以可行,是因为外层布局是RelativeLayout。

那么,如果外层布局换做LinearLayout又会怎样呢?答案显而易见,这肯定是行不通的。那么怎么办呢?我们可以把具体的属性写在<include/>标签里面,看下面的代码。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal"
        android:text="@string/hello"/>
    <include
        layout="@layout/footer"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="30dp"/>
</RelativeLayout>
我们直接在<include/>标签里面使用了android:layout_*属性。

注意:如果想要在<include/>标签中覆盖被包含布局所指定的任何android:layout_*属性,必须在<include/>标签中同时指定layout_width和layout_height属性,这可能是一个Android系统的一个bug吧。


ViewStub
在开发过程中,难免会遇到各种交互问题,例如显示或隐藏某个视图。如果想要一个视图只在需要的时候显示,可以尝试使用ViewStub这个类。

先看一下ViewStub的官方介绍:

“ViewStub是一个不可视并且大小为0的视图,可以延迟到运行时填充布局资源。当ViewStub设置为Visible或调用inflate()之后,就会填充布局资源,ViewStub便会被填充的视图替代”。

现在已经清楚ViewStub能干什么了,那么看一个例子。一个布局中,存在一个MapView,只有需要它的时候,才让它显示出来。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:onClick="onShowMap"
        android:text="@string/show_map" />

    <ViewStub
        android:id="@+id/map_stub"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:inflatedId="@+id/map_view"
        android:layout="@layout/map" />

</RelativeLayout>

map.xml文件中包含一个MapView,只有在必要的时候,才会让它显示出来。

<com.google.android.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/map_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:apiKey="my_api_key"
    android:clickable="true" />

另外,inflatedId是ViewStub被设置成Visible或调用inflate()方法后返回的id,这个id就是被填充的View的id。在这个例子中,就是MapView的id。

接下来看看ViewStub是怎么使用的。

public class MainActivity extends MapActivity {

  private View mViewStub;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mViewStub = findViewById(R.id.map_stub);
  }

  public void onShowMap(View v) {
    mViewStub.setVisibility(View.VISIBLE);
  }

  @Override
  protected boolean isRouteDisplayed() {
    return false;
  }
}


题外话

有的同学肯定会问,使用ViewStub和单纯地把View设置为View.GONE或View.VISIBLE有什么区别呢?不都是显示和隐藏吗,使用ViewStub反而更麻烦了。

确实是有区别的,会涉及到View树的渲染,内存消耗等。

至于有什么具体的差别,就请大家自己去Google吧。俗话说,自己动手,丰衣足食嘛!


参考资料

http://code.google.com/p/android/issues/detail?id=2863

http://android-developers.blogspot.com.ar/2009/03/android-layout-tricks-3-optimize-with.html

http://developer.android.com/reference/android/view/ViewStub.html


作者:manoel 发表于2014-9-4 0:24:49 原文链接
阅读:225 评论:0 查看评论

相关 [android 开发 技巧] 推荐:

【Android 开发技巧】布局优化利器<include/>和ViewStub

- - CSDN博客移动开发推荐文章
『原创作品,转载请注明出处. 〔文章原始地址  http://blog.csdn.net/manoel/article/details/39036507〕. 当创建复杂的布局的时候,有时候会发现添加了很多的ViewGroup和View. 随之而来的问题是View树的层次越来越深,应用也变的越来越慢,因为UI渲染是非常耗时的.

Android开发Tips

- - CSDN博客推荐文章
欢迎Follow我的 GitHub, 关注我的 CSDN.. 介绍一些, 在Android开发中, 会经常使用的小知识点.. submodule与git可以保持实时同步. 导入, 路径多于一个, 前面不添加冒号(:).. 使用PackageManager.. // 检查App是否安装 private boolean appInstalledOrNot(String uri) {.

Android调试程序技巧

- - ITeye博客
在开发的过程中我们经常需要调试程序的执行路径,如我们想知道一个Activity的生命周期方法的调用顺序,我们可能会写如下代码. 这样每次都要输入两个参数,有没有更简便的方法呢. 我们可以通过Thread.currentThread().getStackTrace()获取当前堆栈调用信息,从堆栈信息中可以获取当前调用的java文件名,类名,方法名和代码行号.

Android实战技巧:多线程AsyncTask

- - CSDN博客推荐文章
AsyncTask是Android 1.5 Cubake加入的用于实现异步操作的一个类,在此之前只能用Java SE库中的Thread来实现多线程异步,AsyncTask是Android平台自己的异步工具,融入了Android平台的特性,让异步操作更加的安全,方便和实用. 实质上它也是对Java SE库中Thread的一个封装,加上了平台相关的特性,所以对于所有的多线程异步都强烈推荐使用AsyncTask,因为它考虑,也融入了Android平台的特性,更加的安全和高效.

21个Android手机使用小技巧

- - 译言-电脑/网络/数码科技
Android能让用户在桌面创建联系人图标. 长按桌面空白处,当弹出菜单后,选择:快捷方式>联系人,然后就可以在列表里选择想要添加的联系人. 对于冰激凌三明治(ICS)用户就更简单了,直接在首页使用插件菜单中的:”联系人“,”直接拨号“或者”直接发送信息“小插件. 你也可以将联系人分组到不同的文件夹中.

Android代码优化小技巧总结

- - 移动开发 - ITeye博客
关注微信号:javalearns   随时随地学Java. 这篇文章主要是介绍了一些小细节的优化技巧,当这些小技巧综合使用起来的时候,对于整个Android App的性能提升还是有作用的,只是不能较大幅度的提升性能而已. 选择合适的算法与数据结构才应该是你首要考虑的因素,在这篇文章中不会涉及这方面.

Android Java层的anti-hooking技巧

- - WooYun知识库
原文: http://d3adend.org/blog/?p=589. 一个最近关于检测native hook框架的方法让我开始思考一个Android应用如何在Java层检测Cydia Substrate或者Xposed框架. 下文所有的anti-hooking技巧很容易就可以被有经验的逆向人员绕过,这里只是展示几个检测的方法.

Android 开发者调查

- - 爱范儿 · Beats of Bits
Startup 是为 Android 开发者提供盈利模式的一个公司. Android 开发者只要在应用上推广 Startup 服务,并且为网站带去流量,就可以得到网站给予的补贴. 今年 3 月的时候,Startup 网站对 Android 开发者进行了一次调查. 现在,他们将调查的结果制成了信息图,并 发布在网站之上.

Android敏捷开发指南

- - 互联网的那点事
本文紧密结合移动开发方法与技术,围绕Android平台的开发探讨提供更高质量移动产品的解决方案. 作者中分析了移动开发中常见的问题,从两方面阐述了ThoughtWorks使用的测试开发方案和相应的架构方法与常用工具应用,并进一步阐述了为移动开发流程所提供的持续发布方案. 随着云计算、移动互联等一系列新技术概念的崛起,新一轮的IT经济正在不断扩大发展.

Android应用开发资源

- - InfoQ cn
Android应用设计和开发人员现在可以参考由Android用户体验(UX)团队官方发布的 Android设计指南. 该指南提供了开发者应该遵循的基本原则,并列出了很多细节指导,涉及 设备与显示、 主题、 触控交互、 度量与栅格、 排版、 色彩、 图标设计,以及如何 编写用户交互界面的提示语.