android之ViewStub解析

android中,很多地方在提到布局优化都会提到使用ViewStub.可能很多人都只是用她,而没有去看看ViewStub到底是个什么东西,器特殊的功能是如何实现的!这里,我来解析一下我们的ViewStub.

打开ViewStub.java,你会发现其实ViewStub就是一个view的子类,和其他framework的java文件一样,google都给了一个说明.其实通过这个说明,你基本就知道ViewStub的属性和使用方法来.这里我就通过她的说明开始入手.

下面我们来看第一段原文说明:

 * A ViewStub is an invisible, zero-sized View that can be used to lazily inflate
 * layout resources at runtime.

这一句英文说明指出来ViewStub的几乎所有特点:(1)不可见的(invisible);(2)没有大小的(zero-sized);(3)能够用于在运行时候延迟加载的.下面来看看,她是如何实现这三个特点的!

(1)不可见的(invisible): 在初始化ViewStub的时候,构造函数就会调用这个方法:initialize,来把这个view(ViewStub)设置为GONE,请看如下源码:

    private void initialize(Context context) {
        mContext = context;
        setVisibility(GONE);
        setWillNotDraw(true);
    }

setVisibility(GONE);就时把这个view设置成GONE,也就是说我们这个ViewStub默认情况下就是会被初始化成一个GONE的view,这样以来在布局文件加载的时候,这个ViewStub被视为不可见的!

此外还调用了这个方法:setWillNotDraw(true);这样一来,该view的onDraw就不会执行!

其实,我个人认为:原文的说明:A ViewStub is an invisible,其实不仅仅是调用上面这两个方法来实现的, 通过查看ViewStub这个类,你会发现,ViewStub来从写来父类(view)的两个方法draw和dispatchDraw以及onMeasure, 以此来覆盖父类的这两个方法.下面是ViewStub对方法draw和dispatchDraw以及onMeasure从写的源码:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(0, 0);
    }

    @Override
    public void draw(Canvas canvas) {
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
    }

看了上面代码,你肯定会吃惊,draw和dispatchDraw都是什么也不做! 并且onMeasure还什么也不做,直接setMeasuredDimension(0, 0);来把view区域设置位0. 看到这几行源码你就不得不明白,原来一个ViewStub虽然是一个view,却是一个没有任何显示内容,也不显示任何内容的特殊view,并且对layout在加载时候不可见的.

原文的说明还有最后一段:lazily inflate layout resources at runtime. 延迟inflate? 在运行的时候?

来看看接下来的一段说明:

 * When a ViewStub is made visible, or when {@link #inflate()}  is invoked, the layout resource
 * is inflated. The ViewStub then replaces itself in its parent with the inflated View or Views.
 * Therefore, the ViewStub exists in the view hierarchy until {@link #setVisibility(int)} or
 * {@link #inflate()} is invoked.

上面的大意是: 当把这个ViewStub设置为visible,或者调用inflate()的时候,这个ViewStubde 的layout就会inflated,并且用inflated出的view替换原来ViewStub在整个布局的位置.

说起来有点复杂,我们来看看下面的源码:

    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();
            }
        }
    }

重写来父类的方法,通过上面方法可以知道,如果mInflatedViewRef为null,并且visibility == VISIBLE || visibility == INVISIBLE) 就会调用的inflate(); 实际上inflate()做的就是初始化这个ViewStub的内容,并且替换自己(ViewStub), 这里的mInflatedViewRef其实就是inflate()初始化的内容view,所以在上面的setVisibility首先要看看这个ViewStub是否已经inflate()了.

下面来看看inflate()这个方法的源码:

    public View inflate() {
        final ViewParent viewParent = getParent();

        if (viewParent != null && viewParent instanceof ViewGroup) {
            if (mLayoutResource != 0) {
                final ViewGroup parent = (ViewGroup) viewParent;
                final LayoutInflater factory;
                if (mInflater != null) {
                    factory = mInflater;
                } else {
                    factory = LayoutInflater.from(mContext);
                }
<span style="color:#FF0000;">                final View view = factory.inflate(mLayoutResource, parent,
                        false);</span>

                if (mInflatedId != NO_ID) {
                    view.setId(mInflatedId);
                }

                final int index = parent.indexOfChild(this);
               <span style="color:#FF0000;"> parent.removeViewInLayout(this);</span>

                final ViewGroup.LayoutParams layoutParams = getLayoutParams();
                if (layoutParams != null) {
                    <span style="color:#FF0000;">parent.addView(view, index, layoutParams);</span>
                } else {
                    <span style="color:#FF0000;">parent.addView(view, index);</span>
                }

                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");
        }
    }

通过上面的代码,你应该很清楚了,这里的mLayoutResource其实在ViewStub初始化的时候就会被赋值的.看看源码:

    public ViewStub(Context context, AttributeSet attrs, int defStyle) {
        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewStub,
                defStyle, 0);

        mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
        <span style="background-color: rgb(255, 0, 0);">mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);</span>

        a.recycle();

        a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View, defStyle, 0);
        mID = a.getResourceId(R.styleable.View_id, NO_ID);
        a.recycle();

        initialize(context);
    }

google其实还给出了使用方法的说明:

 *     ViewStub stub = (ViewStub) findViewById(R.id.stub);
 *     View inflated = stub.inflate();
时间: 2024-10-10 09:41:12

android之ViewStub解析的相关文章

Android Service完全解析,关于服务你所需知道的一切(下) (转载)

转自:http://blog.csdn.net/guolin_blog/article/details/9797169 转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在 上一篇文章中,我们学习了Android Service相关的许多重要内容,包括Service的基本用法.Service和Activity进行通信.Service的销毁方式. Service与Thread的关系.以及如何创建前台Service.以上

Android Service完全解析,关于服务你所需知道的一切(上)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11952435 相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的Android程序员如果连Service都没听说过的话,那确实也太逊了.Service作为Android四大组件之一,在每一个应用程序中都扮演着非常重要的角色.它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务.必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持

Android ActionBar完全解析,使用官方推荐的最佳导航栏(下)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/25466665 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文. http://developer.android.com/guide/topics/ui/actionbar.html 限于篇幅的原因,在上篇文章中我们只学习了ActionBar基础部分的知识,那么本篇文章我们将接着上一章的内容继续学习,探究一下ActionBar

Android ActionBar完全解析,使用官方推荐的最佳导航栏(上)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/18234477 本篇文章主要内容来自于Android Doc,我翻译之后又做了些加工,英文好的朋友也可以直接去读原文. http://developer.android.com/guide/topics/ui/actionbar.html Action Bar是一种新増的导航栏功能,在Android 3.0之后加入到系统的API当中,它标识了用户当前操作界面的位置,并提供了额外的用

Android Service完全解析,关于服务你所需知道的一切(下)

转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要内容,包括Service的基本用法.Service和Activity进行通信.Service的销毁方式.Service与Thread的关系.以及如何创建前台Service.以上所提到的这些知识点,基本上涵盖了大部分日常开发工作当中可能使用到的Service技术.不过关于Service其实还有一个更加

Android JSON原生解析的几种思路,以号码归属地,笑话大全,天气预报为例演示

Android JSON原生解析的几种思路,以天气预报为例 今天项目中要实现一个天气的预览,加载的信息很多,字段也很多,所以理清了一下思路,准备独立出来写一个总结,这样对大家还是很有帮助的,老司机要开车了 涉及到网络,你就一定要先添加权限,准没错 <!--网络权限--> <uses-permission android:name="android.permission.INTERNET" /> 一.归属地查询(JSONObject) 这个也是最简单的一类Json

基于Android2.3.5系统:Android.mk文件解析

*************************************************************************************************************************** 作者:EasyWave                                                                                                               时间:2

CountDownLatch &amp; CyclicBarrier源码Android版实现解析

CountDownLatch CountDownLatch允许一条或者多条线程等待直至其它线程完成以系列的操作的辅助同步器. 用一个指定的count值对CountDownLatch进行初始化.await方法会阻塞,直至因为调用countDown方法把当前的count降为0,在这以后,所有的等待线程会被释放,并且在这以后的await调用将会立即返回.这是一个一次性行为--count不能被重置.如果你需要一个可以重置count的版本,考虑使用CyclicBarrier. 其实本类实现非常简单,和Re

【Android进阶】解析XML文件之使用DOM解析器

在前面的文章中,介绍了使用SAX解析器对XML文件进行解析,SAX解析器的优点就是占用内存小.这篇文章主要介绍使用DOM解析器对XML文件进行解析.DOM解析器的优点可能是理解起来比较的直观,当然,每个人对不同的解析方法可能有不同的喜好.但是DOM解析器有个比较大的缺点,就是占用内存比较多,在Android中的XML解析中,还是更推荐其他的解析方式. 下面介绍使用DOM解析器对XML进行解析. 下面是我们需要解析的xml文件 <?xml version="1.0" encodin