资讯专栏INFORMATION COLUMN

Android布局优化:ViewStub标签实现延迟加载(源码解析原理)

Raaabbit / 960人阅读

摘要:好处官方对的解析一个不可见大小为的试图下面会分析这两点实现好处显示优酷视频加载评论列表的,当没有数据或者网络加载失败时,如果空列表的会占用资源当有数据时,才会列表的,延迟加载了布局使用步骤文件每一个必须有属性,其中的值就是被的的可以通过这

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()方法绘制内容
    }
@Override
protected 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);
}
    

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67543.html

相关文章

  • Android布局优化ViewStub标签实现延迟加载源码解析原理

    摘要:好处官方对的解析一个不可见大小为的试图下面会分析这两点实现好处显示优酷视频加载评论列表的,当没有数据或者网络加载失败时,如果空列表的会占用资源当有数据时,才会列表的,延迟加载了布局使用步骤文件每一个必须有属性,其中的值就是被的的可以通过这 1.ViewStub好处 ViewStub is a lightweight view with no dimension that doesn’...

    rose 评论0 收藏0
  • Android ViewStub的使用

    摘要:如果布局实现的不好,会导致程序非常占内存并且运行缓慢。优化布局可以从三个方面着手使用标签重用使用标签避免冗余的布局嵌套使用实现按需加载本文讲解一下的使用。下面两幅图分别是点击前后的界面注意不支持使用标签的布局。 简介 在Android开发中,布局的加载速度会影响APP的性能。如果布局实现的不好,会导致程序非常占内存并且UI运行缓慢。优化布局可以从三个方面着手: 使用标签重用layou...

    youkede 评论0 收藏0
  • 性能优化1--UI优化

    摘要:若指定了其他的的这种属性,则和必须存在。否则其他的无法生效按需加载标签和标签很相似,都是使用属性来加载一个布局。提高了程序性能。其实这种说法是错误的。减少布局层数标签用来取消的层级的显示。1.使用系统为我们提供了几个抽象的标签 ①include:重用 include中layout属性指定一个外部布局文件,通过该方式则不需要把这个布局文件在该代码中重复的写一遍了。 若include指定了...

    tomorrowwu 评论0 收藏0
  • Android布局优化三剑客

    摘要:要解决这些痛点,我们可以请布局优化三剑客出码,它们分别是和三个标签,现在我们就来认识认识它们吧。此时如果想要再次显示布局,可以调用方法。通过监听的填充事件声明一个布尔值变量,默认值为,布局填充成功之后,在监听事件方法中将其置为。 前言 在编写Android布局时总会遇到这样或者那样的痛点,比如: 有些布局的在很多页面都用到了,而且样式都一样,每次用到都要复制粘贴一大段,有没有办法可以...

    alaege 评论0 收藏0
  • Android优化总结

    摘要:错误使用单利在开发中单例经常需要持有对象,如果持有的对象生命周期与单例生命周期更短时,或导致无法被释放回收,则有可能造成内存泄漏。如果集合是类型的话,那内存泄漏情况就会更为严重。 目录介绍 1.OOM和崩溃优化 1.1 OOM优化 1.2 ANR优化 1.3 Crash优化 2.内存泄漏优化 2.0 动画资源未释放 2.1 错误使用单利 2.2 错误使用静态变量 2.3 ...

    sunsmell 评论0 收藏0

发表评论

0条评论

Raaabbit

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<