跳至主要內容

RecyclerView原理


Android开发RecyclerView的内容更新流程

RecyclerView是如何更新的呢?

我们调用一个notifiDateSetChange以后发生了什么事情呢?

我们从中可以学习到什么思想呢?

如何使用RecyclerView

  • 创建/从布局中找到RecyclerView控件
  • 创建布局管理器,设置布局管理器(很多刚学习的同学会忘记这个步骤)
  • 创建适配器,设置适配器
  • 给适配器设置数据

这里面有几个点:

  1. RecyclerView
  2. 布局管理器
  3. 适配器
  4. 数据

数据更新时,如何让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,那么我们就关心这个东西是怎么来的,什么时候创建/或者设置进来的。

小技巧,搜索创建/赋值的地方,可以加多等号来搜索。

20191102_202609.png
20191102_202609.png

mObservable它也是属于适配器里的对吧!那我们下一步干嘛?当然是搜索它使用的地方看看情况。

小技巧:搜索调用的地方可以mObservable.来搜索,加个点:

20191102_205119.png
20191102_205119.png
20191102_205143.png
20191102_205143.png

主要是两类,个是设置/取消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);
        }

那在哪里注册的呢?

20191102_205532.png
20191102_205532.png

其实两个都一样的,只是我这里一个是sdk里的,一个是support包里的:

点击跳转以后:

20191102_210048.png
20191102_210048.png

继续往前走:

20191102_210118.png
20191102_210118.png

到这里,我们就知道了。原来如此!

当我们给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,请求重新布局。这时,就会重新从适配器里载布局了。

好啦!欢迎大家也分享自己阅读源码的记录。