RecyclerView原理
Android开发RecyclerView的内容更新流程
RecyclerView是如何更新的呢?
我们调用一个notifiDateSetChange以后发生了什么事情呢?
我们从中可以学习到什么思想呢?
如何使用RecyclerView
- 创建/从布局中找到RecyclerView控件
- 创建布局管理器,设置布局管理器(很多刚学习的同学会忘记这个步骤)
- 创建适配器,设置适配器
- 给适配器设置数据
这里面有几个点:
- RecyclerView
- 布局管理器
- 适配器
- 数据
数据更新时,如何让UI更新呢?
数据改变,我们调用适配器里的notifyDateSetChange方法,UI更新
data --> adapter --> recyclerView
为什么RecyclerView不是调用RecyclerView.notifyDateSetChange呢?对吧!面向对象的思想。那如果说是因为数据在adapter里头,所以调用adapter.notifyDatesetChange也说得过去,那么,调用notifyDateSetChange以后,怎么会让RecyclerView更新呢?adapter不持有RecyclerView的引用呀,不是adapter.setRecyclerView(recyclerView)呀,对吧!
接下来我们就阅读一下源码,adapter跟recyclerView是如何通讯的!
源码分析
从适配器的notifyDataSetChange开始说起:
mTestAdapter.notifyDataSetChanged();
public final void notifyDataSetChanged() {
mObservable.notifyChanged();
}
这就是adapter里头的notifyDataSetChanged方法,也就是说我们调用了notifyDataSetChanged以后,它就会调用mObservable里的notifyChanged方法。
好,路子来了!
mObservable,那么我们就关心这个东西是怎么来的,什么时候创建/或者设置进来的。
小技巧,搜索创建/赋值的地方,可以加多等号来搜索。
mObservable它也是属于适配器里的对吧!那我们下一步干嘛?当然是搜索它使用的地方看看情况。
小技巧:搜索调用的地方可以mObservable.来搜索,加个点:
主要是两类,个是设置/取消Observer,一类是更新的调用。
那我们就看看这里更新的调用了。因为我们更新就是调用这个方法的呀:
public final void notifyDataSetChanged() {
mObservable.notifyChanged();
}
代码如下:
public void notifyChanged() {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
所以,实际的操作就是遍历集合里的每一个Observer,然后调用其对应的方法,也就是说,重点在注册的地方:
public void registerAdapterDataObserver(AdapterDataObserver observer) {
mObservable.registerObserver(observer);
}
那在哪里注册的呢?
其实两个都一样的,只是我这里一个是sdk里的,一个是support包里的:
点击跳转以后:
继续往前走:
到这里,我们就知道了。原来如此!
当我们给RecyclerView设置适配器的 时候,ReyclclerView反给adapter设置一个Observer
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
这个类的具体
private class RecyclerViewDataObserver extends AdapterDataObserver {
RecyclerViewDataObserver() {
}
@Override
public void onChanged() {
assertNotInLayoutOrScroll(null);
mState.mStructureChanged = true;
setDataSetChangedAfterLayout();
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
triggerUpdateProcessor();
}
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) {
triggerUpdateProcessor();
}
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeRemoved(positionStart, itemCount)) {
triggerUpdateProcessor();
}
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeMoved(fromPosition, toPosition, itemCount)) {
triggerUpdateProcessor();
}
}
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
}
所以,当我们调用notifyDatesetChange的时候,就调用RecyclerView设置过来Observer里的onChange方法
@Override
public void onChanged() {
assertNotInLayoutOrScroll(null);
mState.mStructureChanged = true;
setDataSetChangedAfterLayout();
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
而onChange方法则调用requireLayout,请求重新布局。这时,就会重新从适配器里载布局了。
好啦!欢迎大家也分享自己阅读源码的记录。