Android性能优化之ViewStub
http://www.cnblogs.com/lwbqqyumidi/p/4047108.html
ViewStub是Android布局优化中一个很不错的标签/控件,直接继承自View。虽然Android开发人员基本上都听说过,但是真正用的可能不多。
ViewStub可以理解成一个非常轻量级的View,与其他的控件一样,有着自 己的属性及特定的方法。当ViewStub使用在布局文件中时,当程序inflate布局文件时,ViewStub本身也会被解析,且占据内存控件,但是 与其他控件相比,主要区别体现在以下几点:
1.当布局文件inflate时,ViewStub控件虽然也占据内存,但是相相比于其他控件,ViewStub所占内存很小;
2.布局文件inflate时,ViewStub主要是作为一个“占位符”的性 质,放置于view tree中,且ViewStub本身是不可见的。ViewStub中有一个layout属性,指向ViewStub本身可能被替换掉的布局文件,在一定时 机时,通过viewStub.inflate()完成此过程;
3.ViewStub本身是不可见的,对 ViewStub setVisibility(..)与其他控件不一样,ViewStub的setVisibility 成View.VISIBLE或INVISIBLE如果是首次使用,都会自动inflate其指向的布局文件,并替换ViewStub本身,再次使用则是相 当于对其指向的布局文件设置可见性。
这里需要注意的是:
1.ViewStub之所以常称之为“延迟化加载”,是因为在教多数情况下,程序 无需显示ViewStub所指向的布局文件,只有在特定的某些较少条件下,此时ViewStub所指向的布局文件才需要被inflate,且此布局文件直 接将当前ViewStub替换掉,具体是通过viewStub.infalte()或 viewStub.setVisibility(View.VISIBLE)来完成;
2.正确把握住ViewStub的应用场景非常重要,正如如1中所描述需求场景下,使用ViewStub可以优化布局;
3.对ViewStub的inflate操作只能进行一次,因为inflate的 时候是将其指向的布局文件解析inflate并替换掉当前ViewStub本身(由此体现出了ViewStub“占位符”性质),一旦替换后,此时原来的 布局文件中就没有ViewStub控件了,因此,如果多次对ViewStub进行infalte,会出现错误信息:ViewStub must have a non-null ViewGroup viewParent。
4.3中所讲到的ViewStub指向的布局文件解析inflate并替换掉当前 ViewStub本身,并不是完全意义上的替换(与include标签还不太一样),替换时,布局文件的layout params是以ViewStub为准,其他布局属性是以布局文件自身为准。
下面看一下简单的需求场景:在listview显示列表数据时,可能会出现服务端 一条数据都没有的情况,此时显示一个EmptyView,提示用户暂无数据。此时考虑到实际应用中EmptyView显示出来的机会相当小,因此,可以在 布局文件中使用ViewStub站位,然后确实没有数据时才viewStub.infalte()。
相关部分代码如下:
1 public void showEmptyView() {
2 listview.setVisibility(View.GONE);
3 if (noDataView == null) {
4 ViewStub noDataViewStub = (ViewStub) view.findViewById(R.id.no_data_viewstub);
5 noDataView = noDataViewStub.inflate();
6 } else {
7 noDataView.setVisibility(View.VISIBLE);
8 }
9 }
10
11 public void showListView(){
12 listview.setVisibility(View.VISIBLE);
13 if(noDataView != null){
14 noDataView.setVisibility(View.GONE);
15 }
16 }
特别需要注意的是对ViewStub是否已经inflate的判断。
在Listview Item中,有时候可能遇到如下场景:在不同的列表页item的布局一部分不同,但相对于整个item布局来说又不是很多,此时最常见的有如下两种处理:
1.对不同的部分都写出来,放到一个item文件中,然后逻辑分别处理不同部分的显示与否(View.VISIBLE和View.GONE);
2.对这两种不同的item整个部分都分别区分开,完全写成两个item文件,然后结合listView显示不同布局分别做逻辑处理(通过getItemType()等方式)。
以上两种处理方式其实都可以,第一种方式逻辑清晰,非常灵活,只是在一定程度上增 加了内存和资源消耗。第二种方式是的布局文件有重复(虽然相同部分可以通过include,但是逻辑上还是有重复的),包括逻辑上处理的代码实质上的重 复。一般对于有较大不同的item布局推荐采用此种方式。
有时候结合需求,可以在第一种方式的基础上,结合ViewStub“占位符”可以比较好的完成此类需求。也相当于是两种方式的一种折中形式,但同时兼顾了内存和资源消耗以及不同的布局逻辑控件。
笔者水平有限,若有错漏,欢迎指正,欢迎转载以及CV操作,但希注明出处,谢谢!
推荐的做法是使用android.view.ViewStub,ViewStub 是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Inflate布局的时候,只有 ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向 的布局就会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub来方便的在运行时,要还 是不要显示某个布局。
但ViewStub也不是万能的,下面总结下ViewStub能做的事儿和什么时候该用ViewStub,什么时候该用可见性的控制。
首先来说说ViewStub的一些特点:
1. ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。
2. ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。
基于以上的特点,那么可以考虑使用ViewStub的情况有:
1. 在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。
因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和
隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。
2. 想要控制显示与隐藏的是一个布局文件,而非某个View。
因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。
所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View的可见性来控制。
下面来看一个实例
在这个例子中,要显示二种不同的布局,一个是用TextView显示一段文字,另一个则是用ImageView显示一个图片。这二个是在onCreate()时决定是显示哪一个,这里就是应用ViewStub的最佳地点。
先来看看布局,一个是主布局,里面只定义二个ViewStub,一个用来控制TextView一个用来控制ImageView,另外就是一个是为显示文字的做的TextView布局,一个是为ImageView而做的布局:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:gravity="center_horizontal">
- <ViewStub
- android:id="@+id/viewstub_demo_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="5dip"
- android:layout_marginTop="10dip"
- android:layout="@layout/viewstub_demo_text_layout"/>
- <ViewStub
- android:id="@+id/viewstub_demo_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="5dip"
- android:layout="@layout/viewstub_demo_image_layout"/>
- </LinearLayout>
为TextView的布局:
- <?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">
- <TextView
- android:id="@+id/viewstub_demo_textview"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="#aa664411"
- android:textSize="16sp"/>
- </LinearLayout>
为ImageView的布局:
- <?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:id="@+id/viewstub_demo_imageview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
- </LinearLayout>
下面来看代码,决定来显示哪一个,只需要找到相应的ViewStub然后调用其infalte()就可以获得相应想要的布局:
- package com.effective;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.ViewStub;
- import android.widget.ImageView;
- import android.widget.TextView;
- public class ViewStubDemoActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.viewstub_demo_activity);
- if ((((int) (Math.random() * 100)) & 0x01) == 0) {
- // to show text
- // all you have to do is inflate the ViewStub for textview
- ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_text);
- stub.inflate();
- TextView text = (TextView) findViewById(R.id.viewstub_demo_textview);
- text.setText("The tree of liberty must be refreshed from time to time" +
- " with the blood of patroits and tyrants! Freedom is nothing but " +
- "a chance to be better!");
- } else {
- // to show image
- // all you have to do is inflate the ViewStub for imageview
- ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_image);
- stub.inflate();
- ImageView image = (ImageView) findViewById(R.id.viewstub_demo_imageview);
- image.setImageResource(R.drawable.happy_running_dog);
- }
- }
- }
运行结果:
使用的时候的注意事项:
某些布局属性要加在ViewStub而不是实际的布局上面,才会起作用,比如上面用的android:layout_margin*系列属性,如果加在
TextView上面,则不会起作用,需要放在它的ViewStub上面才会起作用。而ViewStub的属性在inflate()后会都传给相应的布
局。
Android性能优化之ViewStub的更多相关文章
- Android性能优化:ViewStub
在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局.那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View.GONE,然后在 ...
- Android性能优化:布局优化 详细解析(含<include>、<ViewStub>、<merge>讲解 )
1. 影响的性能 布局性能的好坏 主要影响 :Android应用中的页面显示速度 2. 如何影响性能 布局影响Android性能的实质:页面的测量 & 绘制时间 1个页面通过递归 完成测量 & ...
- android 性能优化
本章介绍android高级开发中,对于性能方面的处理.主要包括电量,视图,内存三个性能方面的知识点. 1.视图性能 (1)Overdraw简介 Overdraw就是过度绘制,是指在一帧的时间内(16. ...
- Android性能优化系列 + Android官方培训课程中文版
Android性能优化典范 - 第6季 http://hukai.me/android-performance-patterns-season-6/ Android性能优化典范 - 第5季 htt ...
- Android性能优化之布局优化
最新最准确内容建议直接访问原文:Android性能优化之布局优化 本文为Android性能优化的第二篇——布局优化,主要介绍使用抽象布局标签(include, viewstub, merge).去除不 ...
- 【转】Android性能优化之布局优化篇
转自:http://blog.csdn.net/feiduclear_up/article/details/46670433 Android性能优化之布局优化篇 分类: andorid 开发2015 ...
- 《Android开发艺术探索》读书笔记 (13) 第13章 综合技术、第14章 JNI和NDK编程、第15章 Android性能优化
第13章 综合技术 13.1 使用CrashHandler来获取应用的Crash信息 (1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?利用Thread类的set ...
- android性能优化的一些东西
说到android性能优化,总觉得是一个很模糊的东西,因为app的性能始终适合手机本身的性能挂钩的,也许一些消耗内容的操作,在一些移动设备可以运行,但是在另外一些上面就会出现内存溢出的问题,但是不管怎 ...
- Android性能优化之启动速度优化
Android性能优化之启动速度优化 Android app 启动速度优化,首先谈谈为什么会走到优化这一步,如果一开始创建 app 项目的时候就把这个启动速度考虑进去,那么肯定就不需要重新再来优化 ...
随机推荐
- Stanford Parser学习入门(1)-Eclipse中配置
Stanford Parser是斯坦福大学研发的用于语法分析的工具,属于stanford nlp系列工具之一.本文主要介绍Standfor Parser的入门用法. 在Stanford官方网站下载最新 ...
- html5自定义标签选择器
* E[attr]:只使用属性名,但没有确定任何属性值 * E[attr="value"]:指定属性名,并指定了该属性的属性值.必须和元素的属性完全匹配 * E[attr~=&qu ...
- HTTP之Content-Length
在HTTP协议中,有Content-Length的详细解读.Content-Length用于描述HTTP消息实体的传输长度the transfer-length of the message-body ...
- 创建LIST分区
一:创建分区表 create table T_PM_ACCT_DTL_AF_TEST ( DATA_DATE NUMBER(8), ACCT_NO VARCHAR2(100), ACCT_ORD VA ...
- 网络流CodeForces. Original 589F:Gourmet and Banquet
A gourmet came into the banquet hall, where the cooks suggested n dishes for guests. The gourmet kno ...
- Y86处理器的各个阶段
0x00e:30f480000000 | irmovl $128,%esp 实现所有Y86指令所需要的计算分为6个基本阶段:取值.译码.执行.访存.写回和更新 ...
- 手把手教你学习DSP_硬件设计
<<手把手教你学习DSP>>顾卫刚,感觉写的不错,将感兴趣的部分摘录下俩. 1.A/D保护及矫正电路 TMS320X2812 AD输入为0-3V,用上述电路可以起到钳位作用.当 ...
- leetcode 栈 括号匹配
https://oj.leetcode.com/problems/valid-parentheses/ 遇到左括号入栈,遇到右括号出栈找匹配,为空或不匹配为空, public class Soluti ...
- Google文档
本博文的主要内容有 .Google文档的介绍 1.Google文档的介绍 https://zh.wikipedia.org/wiki/Google%E6%96%87%E4%BB%B6 http://d ...
- mysql登录时,ERROR 1045 (28000): 错误解决办法
错误问题的描述: ERROR 1045 (28000): Access denied for user 'ODBC'@'localhost' (using password: NO) ERROR 10 ...