我的Android进阶之旅------>Android中的布局优化 include、merge 、ViewStub
1、如何重用布局文件?
可以使用<include>标签引用其他的布局文件,并用android:id属性覆盖被引用布局文件中顶层节点的android:id属性值。代码如下:
<!--引用mylayout.xml-->
<include android:id="@+id/layout1" layout="@layout/mylayout"/>
2、减少视图层级<merge />
3、需要时使用<ViewStub />
<ViewStub />标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用<ViewStub />标签,以减少内存使用量,加快渲染速度。<ViewStub />是一个不可见的,大小为0的View。<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) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
- // or
- View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
当调用inflate()函数的时候,ViewStub被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数findViewById()来查找了。
注:ViewStub目前有个缺陷就是还不支持 <merge
/> 标签。
==================================================================================================
1、merge
顾名思义,就是合并、融合的意思。使用它可以有效的将某些符合条件的多余的层级优化掉。使用merge的场合主要有两处:
(1) 自定义View中使用,父元素尽量是FrameLayout,当然如果父元素是其他布局,而且不是太复杂的情况下也是可以使用的
(2) Activity中的整体布局,根元素需要是FrameLayout
下面这个例子将融合这两种情况,来展示如何缩减布局层次。
总体显示界面如图所示:

其中粉红色圈住的部分为我们的自定义View。
整个界面的布局layout_mergedemo.xml如下:
- <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:textSize="25sp"
- android:textColor="#FF0000FF"
- android:gravity="center_horizontal"
- android:text="我的家园"/>
- <com.example.myandroiddemo.MyItemView
- android:id="@+id/myitem_view"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center" />
- </FrameLayout>
自定义布局view_item.xml如下:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="horizontal" >
- <ImageView
- android:id="@+id/view_item_img"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:scaleType="fitXY"/>
- <TextView
- android:id="@+id/view_item_txt"
- android:layout_width="fill_parent"
- android:layout_height="50dp"
- android:gravity="center_vertical"
- android:layout_marginLeft="10dp"
- android:textSize="20sp"
- android:textColor="#FFFF0000"/>
- </LinearLayout>
自定义View中使用下面来解析布局:
- public class MyItemView extends LinearLayout {
- ......
- private void initView(Context context) {
- mContext = context;
- View view = LayoutInflater.from(mContext).inflate(R.layout.view_item, this, true);
- mMyItemImg = (ImageView)view.findViewById(R.id.view_item_img);
- mMyItemText = (TextView)view.findViewById(R.id.view_item_txt);
- }
- ......
- }
整个功能开发完成之后,使用hierarchyviewer来看一下布局层次:
我们发现简单的一个功能竟然使用了六层布局,包括每个Window自动添加的PhoneWindow$DecorView和FrameLayout(id/content)。明显可以看到这个布局存在冗余,比如第二层和第三层的FrameLayout,比如第四层的MyItemView(LinearLayout子类)和第五层的LinearLayout,都可以缩减。
好了,该我们的merge标签大显身手了。将布局这样修改:
简化layout_mergedemo.xml:
- <merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools">
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:textSize="25sp"
- android:textColor="#FF0000FF"
- android:gravity="center_horizontal"
- android:text="我的家园"/>
- <com.example.myandroiddemo.MyItemView
- android:id="@+id/myitem_view"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center" />
- </merge>
简化view_item.xml:
- <merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" >
- <ImageView
- android:id="@+id/view_item_img"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:scaleType="fitXY"/>
- <TextView
- android:id="@+id/view_item_txt"
- android:layout_width="fill_parent"
- android:layout_height="50dp"
- android:gravity="center_vertical"
- android:layout_marginLeft="10dp"
- android:textSize="20sp"
- android:textColor="#FFFF0000"/>
- </merge>
因为这里merge代替的布局元素为LinearLayout,而不是FrameLayout,所以我们需要在自定义布局代码中将LinearLayout的属性添加上,比如垂直或者水平布局,比如背景色等,此处设置为水平布局:
- private void initView(Context context) {
- setOrientation(LinearLayout.HORIZONTAL);
- ……
- }
OK,就是这么简单,再来看看布局层次吧:
哈哈,只有四层了,加载速度也明显加快,特别是如果布局比较复杂,子View较多的情况下,合理使用merge能大大提高程序的速度和流畅性。
但是使用merge标签还是有一些限制的,具体有以下几点:
(1)merge只能用在布局XML文件的根元素
(2)使用merge来inflate一个布局时,必须指定一个ViewGroup作为其父元素,并且要设置inflate的attachToRoot参数为true。(参照inflate(int, ViewGroup, boolean))
(3)不能在ViewStub中使用merge标签。最直观的一个原因就是ViewStub的inflate方法中根本没有attachToRoot的设置
说到这儿,merge的使用也就讲完了。还想唠叨一下做的演出项目,因为本人水平有限,并且产品提的这个显示需求确实比较BT,所以整个项目的显示框架做了很多嵌套,具体点就是ActivityGroup中嵌套ViewFlipper,然后再嵌套TabHost,然后再嵌套自己的Activity,大体数了一下,最多竟然有20几层,My God!知道Android布局设计的原则是什么吗?最好是10层以下,尽量不要超过15层,如果再多性能就会下降,也可能会出现问题,就是我们看到的StackOverFlow,这个项目被证实也确实在某些低端机上发生了这种错误,比如HTC的某某机型,OPPO的某某机型,(不要声讨我,没有恶意贬低的意思<_>),最终我使用merge缩呀缩呀,把大部分的布局都缩减到了15层以下,一测试,通过!
还要说一下,因为Window窗体(比如Activity)加载时会自动添加PhoneWindow$DecorView和FrameLayout(id/content)两层布局,所以如果我们在Activity的自定义布局根元素中使用merge,而且想设置总体背景什么的,可以用(id/content)将FrameLayout取出来,再设置属性,可以这样实现:
- //setContentView(R.layout.layout_showset);
- FrameLayout frameLayout = (FrameLayout)this.getWindow().getDecorView().findViewById(android.R.id.content);
- frameLayout.setBackgroundResource(R.drawable.bg_repeated_main);
- LayoutInflater.from(this).inflate(R.layout.layout_showset, frameLayout, true);
将setContentView方法摒弃,改由我们手动添加布局。
好了,就这样吧!!!
2、ViewStub
这是什么玩应儿呢?其实就是一个轻量级的页面,我们通常使用它来做预加载处理,来改善页面加载速度和提高流畅性,ViewStub本身不会占用层级,它最终会被它指定的层级取代。
还是说说演出项目吧,还说?对了,实践才能发现问题嘛,在哪儿发现问题就在那儿改进。由于项目中用到了比较多的动画,而且嵌套布局比较复杂,所以在Android低端机上进行页面切换时候经常让人感觉卡卡的,不怎么流畅,因为页面切换动画和标题旋转动画是同时进行的,所以为了达到更好的体验就需要使用一种方法,在动画进行时尽量的减少其他操作,特别是页面加载重绘。赶紧想办法,起初我想先将要加载的页面所有的组件都初始为gone显示状态,整个页面只留一下加载滚动条,后来发现这是不行滴,因为在Android的机制里,即使是将某一个控件的visibility属性设置为不可见的gone,在整个页面加载过程中还是会加载此控件的。再后来就用到了ViewStub,在做页面切换动画时,只在页面中放一个loading加载图标和一个ViewStub标签,像下面这样:
layout_loading.xml布局文件:
- <merge xmlns:android="http://schemas.android.com/apk/res/android">
- <ViewStub
- android:id="@+id/viewstub"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"/>
- <NetErrAndLoadView
- android:id="@+id/start_loading_lay"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" />
- </merge>
这个页面是相当轻量级的,所以导致动画加载速度非常快、而且流畅。等页面切换动画完成之后,我们再指定ViewStub的资源,来加载实际的页面,这个资源就是实际要加载的页面的布局文件。比如要加载MainActivity的布局文件layout_main.xml,onCreate实现如下:
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.layout_loading);
- mLoadHandler = new Handler();
- mLoadingView = (NetErrAndLoadView)findViewById(R.id.start_loading_lay);
- mLoadingView.startLoading();
- mViewStub = (ViewStub)findViewById(R.id.viewstub);
- mViewStub.setLayoutResource(R.layout.layout_main);
- mLoadHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- mViewStub.inflate();
- mLoadingView.hide();
- }
- },500);
- }
上面的500单位是ms,就是延迟加载的时间。上面使用的是动态添加ViewStub指向布局资源的方法(mViewStub.setLayoutResource(R.layout.layout_main)),当然根据需要可以直接在ViewStub的布局块儿中设置,需要设置ViewStub标签下的layout属性(android:layout="@layout/
layout_main")。
ViewStub也是有少许缺点的,下面所说:
1、 ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不能够再通过ViewStub来控制它了。所以它不适用 于需要按需显示隐藏的情况。
2、 ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。如果想操作一个具体的view,还是使用visibility属性吧。
3、 VIewStub中不能嵌套merge标签。(前面好像说过)
不过这些确定都无伤大雅,我们还是能够用ViewStub来做很多事情。
有时候真的不得不佩服google的Android团队的远见性和架构性,这种细微的设计都能考虑的到,想用就有。
3、include
制造这个标签纯碎是为了布局重用,在项目中通常会存在一些布局公用的部分,比如自定义标题,我们不需要把一份代码Ctrl C, Ctrl V的到处都是,严重违背程序简洁化、模块儿化的设计思想,毕竟作为现代化的码农,也需要与时俱进,不再抱着以前那种卖代码的思想来编写程序了(一行代码几个钱?)。这里就不写例子了,随便网上搜一下,include的使用一大堆,简单说一下如何调用吧,比如现在有一个公用布局head.xml,如果在其他的布局中引用,只需要这样添加include标签:
- <include android:layout_width="fill_parent" android:layout_height="wrap_content" layout="@layout/head" />
这个标签下的布局在父布局刷新时候同样是会加载的,所以它即不能像merge那样缩减层级,也不能像ViewStub那样轻量级实现延迟加载,它就是用来布局重用的,各有各的疗效嘛,可以理解。
OK,到这儿我也啰嗦完了,现在脑子里只有一个想法,既然Android的设计者都绞尽脑汁帮我们想到了各种便利用途,我们再不使用就不单是脑子有问题的问题了,就是没把用户需求放在第一位,是得罪上帝的。哈哈,说大了,轻喷。。。。。。不过这几个标签确实很有用,建议在合适的地方都体验一下,还是那句话,谁用谁知道<_>。
说明:以上都是基础内容,只不过可能注意用的人不多,这些标签的使用我也是学习,然后用到了项目当中,本人只是结合自己的理解叙述一遍。如果有更好的改进方法,或者是认为上面的文字有误,欢迎交流。
====================================================================================
作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:http://blog.csdn.net/ouyang_peng
====================================================================================
我的Android进阶之旅------>Android中的布局优化 include、merge 、ViewStub的更多相关文章
- 我的Android进阶之旅------>Android中查看应用签名信息
一.查看自己的证书签名信息 如上一篇文章<我的Android进阶之旅------>Android中制作和查看自定义的Debug版本Android签名证书>地址:http://blog ...
- 我的Android进阶之旅------> Android为TextView组件中显示的文本添加背景色
通过上一篇文章 我的Android进阶之旅------> Android在TextView中显示图片方法 (地址:http://blog.csdn.net/ouyang_peng/article ...
- 我的Android进阶之旅------> Android在TextView中显示图片方法
面试题:请说出Android SDK支持哪些方式显示富文本信息(不同颜色.大小.并包含图像的文本信息),并简要说明实现方法. 答案:Android SDK支持如下显示富文本信息的方式. 1.使用Tex ...
- 我的Android进阶之旅------>Android中AsyncTask源码分析
在我的<我的Android进阶之旅------>android异步加载图片显示,并且对图片进行缓存实例>文章中,先后使用了Handler和AsyncTask两种方式实现异步任务机制. ...
- 我的Android进阶之旅------> Android为TextView组件中显示的文本加入背景色
通过上一篇文章 我的Android进阶之旅------> Android在TextView中显示图片方法 (地址:http://blog.csdn.net/ouyang_peng/article ...
- 我的Android进阶之旅------>Android利用温度传感器实现带动画效果的电子温度计
要想实现带动画效果的电子温度计,需要以下几个知识点: 1.温度传感器相关知识. 2.ScaleAnimation动画相关知识,来进行水印刻度的缩放效果. 3.android:layout_weight ...
- 我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(三)Android客户端功能实现
我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(一)PC服务器端(地址:http://blog.csdn.net/ouyang_pen ...
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之实现游戏逻辑(五)
在上一篇<我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)>中提到的两个类: GameConf:负责管理游戏的 ...
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)
正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piec ...
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)
对于游戏玩家而言,游戏界面上看到的"元素"千变万化:但是对于游戏开发者而言,游戏界面上的元素在底层都是一些数据,不同数据所绘制的图片有所差异而已.因此建立游戏的状态数据模型是实现游 ...
随机推荐
- 2017.4.18 慕课网-spring事务管理总结
1.课程目标 事务回顾 spring中的事务管理的api spring中编程式事务管理 spring中声明式事务管理 2.事务回顾 2.1 事务的概念 事务是指逻辑上的一组操作,要么全成功,要么全失败 ...
- [Algorithms] Classify Mystery Items with the K-Nearest Neighbors Algorithm in JavaScript
The k-nearest neighbors algorithm is used for classification of unknown items and involves calculati ...
- rpc接口mock平台
转载:http://blog.csdn.net/ronghuanye/article/details/71124320 1.简介 平台采用struts.spring.mybatis框架开发设计,主要用 ...
- js 参数校验器
//校验器 var validate = { //校验当前运行环境是否是手机端 isWap:function(){ var sUserAgent= navigator.userAgent.toLowe ...
- 怎样在QML应用中调用系统设置中的页面来设置我们的系统
我们在QML应用中有时须要调用系统设置(system settings)来完毕我们的一些设置.比方,我们在使用GPS来定位时,可能GPS并没有打开,假设在我们的应用中直接打开系统中的GPS设置页面,这 ...
- kafka 0.8.1 新producer 源码简单分析
1 背景 最近由于项目需要,需要使用kafka的producer.但是对于c++,kafka官方并没有很好的支持. 在kafka官网上可以找到0.8.x的客户端.可以使用的客户端有C版本客户端,此客户 ...
- Ffmpeg 探测输入源类型
本文主要记录ffmpeg探测输入源的几个点,方便以后查阅代码.虽然项目时间很赶,还是找个时间做个记录, 好记性不如不如备忘录,时间久了终是会忘记.Ffmpeg版本为4.0.2,版本很重要,Ffmpeg ...
- 中小企业 DevOps 从 0 到 1
原文:http://www.sohu.com/a/145065274_262549 今天主要有四个课题: 先聊一聊 DevOps: 然后跟大家聊一聊运维知识的体系和职业发展: 再是中小企业基于开源的 ...
- VBA小功能集合-判断列内是否有重复值
1.判断列内是否有重复值: Dim arrT As Range Dim rng As Range Set arrT = Range("A:A")'判读A列单元格 For Each ...
- C# 接口的隐式与显示实现说明
以前在用到接口时,从来没注意到接口分为隐式实现与显示实现.昨天在浏览博客时看到相关内容,现在根据自己的理解记录一下,方便日后碰到的时候温习温习. 通俗的来讲,"显示接口实现"就是使 ...


