一、提出疑问

    ViewStub比較简单。之前文章都提及到《Android 性能优化 三 布局优化ViewStub标签的使用》。可是在使用过程中有一个疑惑,究竟是ViewStub上设置的參数有效还是在其包含的layout中设置參数有效?假设不明确描写叙述的问题,能够看下下面布局伪代码。

res/layout/main.xml
<LinearLayout >
<ViewStub
android:id="@+id/viewstub"
android:layout_width="100dip"
android:layout_marginTop="100dip"
android:layout_height="wrap_content"
android:layout="@layout/sub_layout"
/> </LinearLayout> res/layout/sub_layout.xml
<TextView
android:layout_width="50dip"
android:layout_marginTop="50dip"
android:layout_height="wrap_content"
android:text="ViewStub中包括的TextVeiw"/>

    上面的代码中width终于效果是100dip还是50dip?marginTop是100dip还是50dip?带着这个问题一起看下Android 5.0源代码看看ViewStub原理。


    为了便于把ViewStub与其infalte()载入出来的android:layout视图做个区分,下文中针对前者统一命名“ViewStub视图”。后者命名“被 载入视图”,仅为了描写叙述统一并不一定是专业名称。

二、分析ViewStub源代码


    让ViewStub有两种方式一种是调用ViewStub.inflate() 第二种是设置ViewStub.setVisibility(View.VISIBLE); 事实上第二种方式依旧是调用的infalte方法,能够看例如以下ViewStub源代码。
    @Override
@android.view.RemotableViewMethod
public void setVisibility(int visibility) {
if (mInflatedViewRef != null) {
View view = mInflatedViewRef.get();
if (view != null) {
view.setVisibility(visibility);
} else {
throw new IllegalStateException("setVisibility called on un-referenced view");
}
} else {
super.setVisibility(visibility);
if (visibility == VISIBLE || visibility == INVISIBLE) {
inflate();
}
}
}

ViewStub复写了setVisibility方法,并在当中调用infalte方法。以下来看此方法源代码


public final class ViewStub extends View {
...... public View inflate() {
final ViewParent viewParent = getParent(); // 1 为什么能够直接获取父视图? // ViewStub的父视图必须是ViewGroup的子类
if (viewParent != null && viewParent instanceof ViewGroup) {
if (mLayoutResource != 0) { // ViewStub必须设置android:layout属性
final ViewGroup parent = (ViewGroup) viewParent;
final LayoutInflater factory;
if (mInflater != null) {
factory = mInflater;
} else {
factory = LayoutInflater.from(mContext);
}
// 2 inflate被载入视图
final View view = factory.inflate(mLayoutResource, parent,
false); if (mInflatedId != NO_ID) {
view.setId(mInflatedId);
} // 从父视图中获取当前ViewStub在父视图中的位置
final int index = parent.indexOfChild(this);
// 当前ViewStub也是个View只不过用来占位。所以先把占位的ViewStub视图删除
parent.removeViewInLayout(this); // 3 此处获取的是ViewStub上面设置的參数
final ViewGroup.LayoutParams layoutParams = getLayoutParams();
if (layoutParams != null) {
parent.addView(view, index, layoutParams);
} else {
parent.addView(view, index);
} // 目的是在复写的setVisibility方法中使用
// 由于ViewStub.setVisibility操作的是被载入视图并不是当前ViewStub视图
mInflatedViewRef = new WeakReference<View>(view); // 调用监听
if (mInflateListener != null) {
mInflateListener.onInflate(this, view);
} // 返回被载入视图,假设不须要当前能够忽略此返回对象
return view;
} else {
throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
}
} else {
throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
}
}
......
}

以下说下源代码中列出的几点。


 1. 为什么能够直接获取父视图?

ViewStub 继承自View其自身就是一个视图,其调用getParent()能够从父类View上入手、

public class View {
public final ViewParent getParent() {
return mParent;
} void assignParent(ViewParent parent) {
if (mParent == null) {
mParent = parent;
} else if (parent == null) {
mParent = null;
} else {
throw new RuntimeException("view " + this + " being added, but"
+ " it already has a parent");
}
}
}

从View的源代码中获取到,改动mParent參数的仅有assignParent方法且View中并未调用此方法,以下查看下其子类ViewGroup是否有调用。

public class ViewGroup {
public void addView(View child, int index, LayoutParams params) { ...... addViewInner(child, index, params, false);
} private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) { ...... // tell our children
if (preventRequestLayout) {
child.assignParent(this);
} else {
child.mParent = this;
} ......
}
}

从上面源代码能够看到在addView方法中会调用addViewInner,当中调用child.assignParent(this);,把自己全部子视图mParent都设置成当前ViewGroup。

从这一点也能够看出,ViewStub本身是一个View且载入的时候就已经加入到视图树中(View Tree)中,仅接着有另外一个问题既然页面显示的时候ViewStub已经被加入到界面上。为什么有看不到ViewStub视图呢?

疑问:为什么ViewStub尽管是懒载入。可是其自身是一个视图且展示界面就会加入到视图树中,为什么看不到ViewStub?

public final class ViewStub extends View {

    public ViewStub(Context context) {
initialize(context);
} private void initialize(Context context) {
mContext = context;
setVisibility(GONE); // 初始化时把自己设置为隐藏
setWillNotDraw(true);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(0, 0); // 全部子视图都设置为宽高为0
} @Override
public void draw(Canvas canvas) { // 不正确自身与子视图进行绘制
} @Override
protected void dispatchDraw(Canvas canvas) {
}
}

从以上源代码能够看出ViewStub用尽全部办法让自己加入到视图树上是不显示ViewStub自身。



2. inflate被载入视图
    再来看下载入android:layout视图的源代码。
final View view = factory.inflate(mLayoutResource, parent, false);
    能够看到通过infalte方法记载的。其三个參数(int resource, ViewGroup root, boolean attachToRoot),各自是:
mLayoutResource : 设置的android:layout的值
                parent : 通过getParent()获取即ViewStub的父视图
                  false : attachToRoot设置为false说明忽略androd:layout中根节点的layoutParams參数,即width=50dip与margin50dip

3. 视图加入ViewStub.getLayoutParams參数
此处源代码的是获取ViewStub.getLayoutParams參数设置到anroid:layout载入的视图上。 即width=100dip与marginTop=100dip生效。


三、总结
开头的疑问的答案。inflate出来的视图width=100dip与marginTop=100dip而android:layout视图中设置的width50dip和marginTop=50dip失效,等于没有设置。

ViewStub的原理简单描写叙述是
1. ViewStub本身是一个视图。会被加入到界面上,之所以看不到是由于其源代码设置为隐藏与不绘制。
2. 当调用infalte或者ViewStub.setVisibility(View.VISIBLE);时(两个都使用infalte方法逻辑),先从父视图上把当前ViewStub删除。再把载入的android:layotu视图加入上
3. 把ViewStub layoutParams 加入到载入的android:layotu视图上。而其根节点layoutParams 设置无效。
4. ViewStub是指用来占位的视图,通过删除自己并加入android:layout视图达到懒载入效果



从源代码角度分析ViewStub 疑问与原理的更多相关文章

  1. Android的Message Pool是个什么鬼,Message Pool会否引起OOM——源代码角度分析

    引言 Android中,我们在线程之间通信传递通常採用Android的消息机制,而这机制传递的正是Message. 通常.我们使用Message.obtain()和Handler.obtainMess ...

  2. 从信息论的角度分析DNN的工作原理

    在前面的文章里,使用神经网络的任意函数拟合性结合了一点黎曼几何的坐标系变化的知识,解释了神经网络是怎样根据输入x,计算出每个分类下的能量Ei(x)的,再之后使用能量模型推算出了概率,从而展示了理论上可 ...

  3. 反编译字节码角度分析synchronized关键字的原理

    1.synchronized介绍 synchronized是java关键字.JVM规范中,synchronized关键字用于在线程并发执行时,保证同一时刻,只有一个线程可以执行某个代码块或方法:同时还 ...

  4. 从虚拟机指令执行的角度分析JAVA中多态的实现原理

    从虚拟机指令执行的角度分析JAVA中多态的实现原理 前几天突然被一个"家伙"问了几个问题,其中一个是:JAVA中的多态的实现原理是什么? 我一想,这肯定不是从语法的角度来阐释多态吧 ...

  5. 深入浅出!从语义角度分析隐藏在Unity协程背后的原理

    Unity的协程使用起来比较方便,但是由于其封装和隐藏了太多细节,使其看起来比较神秘.比如协程是否是真正的异步执行?协程与线程到底是什么关系?本文将从语义角度来分析隐藏在协程背后的原理,并使用C++来 ...

  6. FFmpeg的HEVC解码器源代码简单分析:CTU解码(CTU Decode)部分-TU

    ===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...

  7. go语言调度器源代码情景分析之二:CPU寄存器

    本文是<go调度器源代码情景分析>系列 第一章 预备知识的第1小节. 寄存器是CPU内部的存储单元,用于存放从内存读取而来的数据(包括指令)和CPU运算的中间结果,之所以要使用寄存器来临时 ...

  8. Linux内核源代码情景分析系列

    http://blog.sina.com.cn/s/blog_6b94d5680101vfqv.html Linux内核源代码情景分析---第五章 文件系统  5.1 概述 构成一个操作系统最重要的就 ...

  9. FFmpeg的HEVC解码器源代码简单分析:CTU解码(CTU Decode)部分-PU

    ===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpe ...

随机推荐

  1. 基于JSP+SERVLET的新闻发布系统(三)

    拖了这么久..今天把栏目管理还有新闻管理模块的也挂出来.. 栏目管理跟用户管理一样. 这里重点讲解新闻管理. 效果图如上: 1,可选择栏目类别,且栏目类别是动态生成的. 默认生成的文章是未审核状态的. ...

  2. activity入门2

    1.如何获取其他应用的包名和类名? 点击和查看logcat第一条信息2.第二步Intent intent = new Intent();intent.setClassName("com.an ...

  3. 演练5-6:Contoso大学校园管理系统6

    在上一次的教程中,我们处理了关联数据问题.这个教程演示如何处理并发问题.你将使用Department实体创建一个页面,这个页面在支持编辑和删除的同时,还可以处理并发错误.下面的截图演示了Index页面 ...

  4. Qt国际化相关类(以前没见过codec->toUnicode,QTextCodec,QLocale.toString和QLocale::setDefault,QInputMethod::locale())

    QTextCodec QTextCodec为文本编码之间提供转换. Qt用Unicode 来存储,绘制和操作字符串.在很多情况下你可能希望操作不同编码的数据.例如,大部分日本文档是以Shift-JIS ...

  5. 关于SSH框架设计的一些理解

    近期在学习企业开发领域非常流行的SSH框架(Struts.Hibernate.Spring).因为之前有做过原生的Servlet+JSP的项目,所以在学习过程中我会跟原生开发模式进行对照,在这里我把自 ...

  6. C语言,C++,static

    术语static有着不寻常的历史.起初,在C中引入关键字static是为了表示退出一个块后仍然存在的局部变量.随后,static在C中有了第二种含义:用来表示不能被其它文件访问的全局变量和函数.为了避 ...

  7. 主题:Java WebService 简单实例

    链接地址:主题:Java WebService 简单实例    http://www.iteye.com/topic/1135747 前言:朋友们开始以下教程前,请先看第五大点的注意事项,以避免不必要 ...

  8. delphi高手突破学习笔记之面向对象类和对象的本质(有汇编解释 good)

    知识点1:堆和栈 每个应用程序可以获得的内存空间分为两种:堆(heap)和栈(stack). 堆又称为“自由存储区”,其中的内存空间的分配与释放是必须由程序员来控制的.例如,用GetMem函数获取了一 ...

  9. EasyUI - Menu 菜单

    效果: html代码: <div id="mm" class="easyui-menu"> <div id =">New< ...

  10. Endnote X6 如何修改输出格式(output style)成为自己想要的输出格式:

    Endnote X6 如何修改输出格式(output style)成为自己想要的输出格式: (1)首先尝试在endnote output style 网站中查找: http://www.endnote ...