android如何延时加载,Android布局优化:ViewStub标签实现延迟加载(源码解析原理)...

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使用步骤

android:id="@+id/list_stub"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout="@layout/stub_list"

android:inflatedId="@+id/stub_list"/>

stub_list.xml文件

xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/list"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

每一个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);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值