一、引言
在平时的开发过程中,当用到滑动布局时,我们用的比较多的是ListView或ScrollView,但对于RecyclerView的使用却比较少,也就是在需要用到水平滑动布局时才会想到RecyclerView。那在有了ListView的情况下,为什么Google还要推出RecyclerView呢?下面我们从源码角度来分析一下该RecyclerView的布局与缓存原理,看看其与ListView有什么区别。
二、源码分析
RecyclerView
一般使用方式是在 Layout
中定义布局文件,然后在 Activity
中通过findViewById
来拿到 RecyclerView
的实例对象,因此我们从 RecyclerView
的构造函数入手进行分析。
public RecyclerView() {
...
if (attrs != null) {
int defStyleRes = 0;
TypedArray a = context.obtainStyledAttributes(attrs, styleable.RecyclerView, defStyle, defStyleRes);
String layoutManagerName = a.getString(styleable.RecyclerView_layoutManager);
...
a.recycle();
this.createLayoutManager(context, layoutManagerName, attrs, defStyle, defStyleRes);
...
}
...
}
构造函数中告诉我们,可以在布局文件中通过 app:layoutManager
来设置 RecyclerView
的 LayoutManager
对象。LayoutManager
主要负责 RecyclerView
的布局。
拿到 RecyclerView
对象后,如果在构造函数中没有设置 LayoutManager
,可以通过调用 RecyclerView
的 setLayoutManager(RecyclerView.LayoutManager layout)
方法进行设置。
public void setLayoutManager(RecyclerView.LayoutManager layout) {
if (layout != this.mLayout) {
...
this.mLayout = layout;
...
}
}
然后 RecyclerView
会调用 setAdapter
方法。
public void setAdapter(RecyclerView.Adapter adapter) {
this.setLayoutFrozen(false);
this.setAdapterInternal(adapter, false, true);
this.requestLayout();
}
setAdapterInternal
方法主要作用是将传进来的 adapter
保存到 mAdapter
变量。之后调用了 requestLayout
方法。
public void requestLayout() {
if (this.mEatRequestLayout == 0 && !this.mLayoutFrozen) {
super.requestLayout();
} else {
this.mLayoutRequestEaten = true;
}
}
requestLayout
方法又调用了父类的 requestLayout
方法,最终调用了 View
的 requestLayout
方法。
public void requestLayout() {
...
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
...
}
上面的 mParent
的真正实例为 ViewRootImpl
,也就是说执行了 ViewRootImpl
的 requestLayout
方法。
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutReque