博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android布局优化:ViewStub标签实现延迟加载(源码解析原理)
阅读量:7126 次
发布时间:2019-06-28

本文共 4925 字,大约阅读时间需要 16 分钟。

1.ViewStub好处

  • ViewStub is a lightweight view with no dimension that doesn’t draw anything or participate in the layout. it's an invisible, zero-sized View that can be used to lazily inflate layout resources at runtime.

    Android官方对ViewStub的解析:1.ViewStub一个不可见2.大小为0的试图. (下面会分析这两点实现)ViewStub好处:显示优酷视频加载评论列表的ListView,当没有数据或者网络加载失败时,如果inflate空列表的ListView会占用资源;当有数据时,才会inflate列表的ListView,延迟加载了布局.

2.ViewStub使用步骤

stub_list.xml文件
  • 每一个ViewStub必须有android:layout属性,其中android:inflatedId的值就是被inflate的View的ID.
  • findViewById(R.id.list_stub)).setVisibility(View.VISIBLE);
    // or
    ListView listView = (ListView)((ViewStub) findViewById(R.id.list_stub)).inflate();

可以通过这两种方式inflate布局,第二种方式inflate布局不需要findViewById()找ListView.查看源码发现,可以通过设置setOnInflateListener()回调监听获取inflate的View.

3.ViewStub源码分析

public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context);        final TypedArray a = context.obtainStyledAttributes(attrs,                R.styleable.ViewStub, defStyleAttr, defStyleRes);        // 解析android:inflatedId属性,其值是被inflate的View的ID        mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);        // 解析android:layout属性,其值是被inflate的View布局        mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);        // 解析android:id属性,可以通过findViewByID找到该ViewStub        mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);        a.recycle();        // 最重要的两点        setVisibility(GONE); // 设置不可见        setWillNotDraw(true); // 本View不会调用onDraw()方法绘制内容    }
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    // 设置试图大小为0    setMeasuredDimension(0, 0);}
public void setVisibility(int visibility) {        if (mInflatedViewRef != null) {            // 已经inflate()已经调用,直接获取该inflate的View控制可见性            View view = mInflatedViewRef.get();            if (view != null) {                view.setVisibility(visibility);            } else {                throw new IllegalStateException("setVisibility called on un-referenced view");            }        } else {            // 如果没有调用过inflate()方法,并且设置了试图可见,就会调用inflate()加载布局            super.setVisibility(visibility);            if (visibility == VISIBLE || visibility == INVISIBLE) {                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);                }                // 加载真正的去加载布局试图                final View view = factory.inflate(mLayoutResource, parent,                        false);                // 设置mInflatedId给inflate的View                if (mInflatedId != NO_ID) {                    view.setId(mInflatedId);                }                // 获取ViewStub在视图中的位置                final int index = parent.indexOfChild(this);                // 从视图移除ViewStub                parent.removeViewInLayout(this);                final ViewGroup.LayoutParams layoutParams = getLayoutParams();                // 将inflate的试图加载父布局中,位置是被移除的ViewStub位置(也就是该ViewStub被替换成layoutView)                if (layoutParams != null) {                    parent.addView(view, index, layoutParams);                } else {                    parent.addView(view, index);                }                mInflatedViewRef = new WeakReference
(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"); }

}

// 设置回调监听public void setOnInflateListener(OnInflateListener inflateListener) {        mInflateListener = inflateListener;    }public static interface OnInflateListener {     // inflated:被inflate的View    void onInflate(ViewStub stub, View inflated);}

4.ViewStub使用中注意事项

  • 一旦调用setVisibility(View.VISIBLE)或者inflate()方法之后,该ViewStub将会从试图中被移除(此时调用findViewById()是找不到该ViewStub对象).
  • 如果指定了mInflatedId , 被inflate的layoutView的id就是mInflatedId.
  • 被inflate的layoutView的layoutParams与ViewStub的layoutParams相同.

以上三点注意的事项可以从源码中得知:

//注意事项第二点if (mInflatedId != NO_ID) {    view.setId(mInflatedId);}//注意事项第一点final int index = parent.indexOfChild(this);parent.removeViewInLayout(this);final ViewGroup.LayoutParams layoutParams = getLayoutParams();if (layoutParams != null) {     //注意事项第三点    parent.addView(view, index, layoutParams);} else {    parent.addView(view, index);}

转载地址:http://oveel.baihongyu.com/

你可能感兴趣的文章
mysql中replace into、replace into、insert ignore用法区别
查看>>
Sql Server系列:数据库组成及系统数据库
查看>>
***之open***
查看>>
tengine+uwsgi+django
查看>>
Django 模板语法取值
查看>>
oracle和sql server 比较
查看>>
高端存储亟待国产化
查看>>
DHCP分配租期问题的重要性
查看>>
linux负载均衡
查看>>
NATIVE SQL的用法
查看>>
JS多项选择删除
查看>>
scrollLeft、offsetLeft、clientLeft、clientHeight详解
查看>>
SQL 到 NOSQL 的思维转变
查看>>
Let's Encrypt,免费好用的 HTTPS 证书
查看>>
for
查看>>
Centos搭建nginx环境,编译,添加服务,开机启动。
查看>>
ubuntu下规避终端打开gvim出现的错误
查看>>
Redis学习——Linux环境下Redis的安装(一)
查看>>
C++继承
查看>>
Android Fragment 真正的完全解析(上)
查看>>