前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于RecyclerView的Adapter的notifyItemInserted()的一些分析

关于RecyclerView的Adapter的notifyItemInserted()的一些分析

作者头像
程序员徐公
发布2018-09-18 16:57:49
3.1K0
发布2018-09-18 16:57:49
举报

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1341895

CSDN 博客地址

本篇文章主要是针对RecyclerView的Adapter的notifyItemInserted()等方法进行分析,不涉及过多的源码分析,毕竟RecyclerView的代码有11037行,个人水平有限。

我们知道RecyclerView的Adapter与ListView的Adapter相比较,主要有一下的几点不同

1)在ListView的Adapter里面,holder这个类是需要我们自己实现的,同时需要我们判断convertView是否为空,典型的做法如下:

代码语言:javascript
复制
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    BaseViewHolder viewHolder = null;
    switch (getItemViewType(position)) {
        case ITEM_MORE://如果是最后一个位置 就显示MoreHolder
            if (convertView == null) {
                viewHolder = getMoreViewHolder();
            } else {
                viewHolder = (BaseViewHolder) convertView.getTag();
            }
            break;
        default://因为可能还有其他不同的条目,所有用defalut,通过getHolder()由子类去返回不同的条目
            if (convertView == null) {
                viewHolder = getHolder();//不能通过构造方法传viewHolder,否则只能显示一个,其他都为空
            } else {
                viewHolder = (BaseViewHolder) convertView.getTag();
            }
            viewHolder.setDataToView(getItem(position));
            break;
    }
    mDisplayedHolders.add(viewHolder);
    return viewHolder.getConvertView();
}

而在RecyclerView的adapter里面,我们不需要判断convertView是否为空,我们只需要写ViewHolder就好了,它会自动帮我们复用 2)RecyclerView的Adpater里面相比较ListView的Adapter,主要多了这几个方法

代码语言:javascript
复制
void notifyItemChanged(int position) 
final void notifyItemChanged(int position, Object payload)
final void notifyItemRangeChanged(int positionStart, int itemCount)
final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload)

那notifyItemInserted(int position)是怎样实现的呢?我们跟踪代码可以发现,会调用以下的方法:

代码语言:javascript
复制
public final void notifyItemInserted(int position) {
    mObservable.notifyItemRangeInserted(position, 1);
}

那这个mObservable到底是什么东西呢?阅读Adapter里面的代码可知,它是里面的一个成员变量,继承于Observable

代码语言:javascript
复制
public static abstract class Adapter<VH extends ViewHolder> {
    private final AdapterDataObservable mObservable = new AdapterDataObservable();

    - - - -
}

我们先来看Observable里面的代码,我们知道这是一个典型的观察者模式的实现。

如果对观察者模式还不了解的,建议先阅读这篇文章:观察者设计模式 Vs 事件委托(java)

代码语言:javascript
复制
public abstract class Observable<T> {
    /**
     * The list of observers.  An observer can be in the list at most
     * once and will never be null.
     */
    protected final ArrayList<T> mObservers = new ArrayList<T>();

    /**
     * Adds an observer to the list. The observer cannot be null and it must not already
     * be registered.
     * @param observer the observer to register
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is already registered
     */
    public void registerObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            if (mObservers.contains(observer)) {
                throw new IllegalStateException("Observer " + observer + " is already registered.");
            }
            mObservers.add(observer);
        }
    }

    /**
     * Removes a previously registered observer. The observer must not be null and it
     * must already have been registered.
     * @param observer the observer to unregister
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is not yet registered
     */
    public void unregisterObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            int index = mObservers.indexOf(observer);
            if (index == -1) {
                throw new IllegalStateException("Observer " + observer + " was not registered.");
            }
            mObservers.remove(index);
        }
    }

    /**
     * Remove all registered observers.
     */
    public void unregisterAll() {
        synchronized(mObservers) {
            mObservers.clear();
        }
    }
}

接着我们来看这个mObservable是在什么时候初始化的呢,我们回到setAdapter()这个方法

代码语言:javascript
复制
public void setAdapter(Adapter adapter) {
    // bail out if layout is frozen
    setLayoutFrozen(false);
    setAdapterInternal(adapter, false, true);
    requestLayout();
}


private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
        boolean removeAndRecycleViews) {
    if (mAdapter != null) {
        mAdapter.unregisterAdapterDataObserver(mObserver);
        mAdapter.onDetachedFromRecyclerView(this);
    }
    if (!compatibleWithPrevious || removeAndRecycleViews) {
        // end all running animations
        if (mItemAnimator != null) {
            mItemAnimator.endAnimations();
        }
        // Since animations are ended, mLayout.children should be equal to
        // recyclerView.children. This may not be true if item animator's end does not work as
        // expected. (e.g. not release children instantly). It is safer to use mLayout's child
        // count.
        if (mLayout != null) {
            mLayout.removeAndRecycleAllViews(mRecycler);
            mLayout.removeAndRecycleScrapInt(mRecycler);
        }
        // we should clear it here before adapters are swapped to ensure correct callbacks.
        mRecycler.clear();
    }
    mAdapterHelper.reset();
    final Adapter oldAdapter = mAdapter;
    mAdapter = adapter;
    if (adapter != null) {
        adapter.registerAdapterDataObserver(mObserver);
        adapter.onAttachedToRecyclerView(this);
    }
    if (mLayout != null) {
        mLayout.onAdapterChanged(oldAdapter, mAdapter);
    }
    mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
    mState.mStructureChanged = true;
    markKnownViewsInvalid();
}

在setAdapterInternal里面主要逻辑就是判断apdter是否为空,不为空的话调用mAdapter.unregisterAdapterDataObserver(mObserver);反注销掉mObserver 接着再调用adapter.registerAdapterDataObserver(mObserver); adapter.onAttachedToRecyclerView(this); 重新注册mObserver和依附到recycleView中。

确定了AdapterDataObservable这个类是什么时候初始化以后,接着我们再回到AdapterDataObservable 这个类

代码语言:javascript
复制
static class AdapterDataObservable extends Observable<AdapterDataObserver> {
    public boolean hasObservers() {
        return !mObservers.isEmpty();
    }

    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();
        }
    }

    public void notifyItemRangeChanged(int positionStart, int itemCount) {
        notifyItemRangeChanged(positionStart, itemCount, null);
    }

    public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
        // since onItemRangeChanged() 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).onItemRangeChanged(positionStart, itemCount, payload);
        }
    }

    public void notifyItemRangeInserted(int positionStart, int itemCount) {
        // since onItemRangeInserted() 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).onItemRangeInserted(positionStart, itemCount);
        }
    }

    public void notifyItemRangeRemoved(int positionStart, int itemCount) {
        // since onItemRangeRemoved() 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).onItemRangeRemoved(positionStart, itemCount);
        }
    }

    public void notifyItemMoved(int fromPosition, int toPosition) {
        for (int i = mObservers.size() - 1; i >= 0; i--) {
            mObservers.get(i).onItemRangeMoved(fromPosition, toPosition, 1);
        }
    }
}

阅读了这个类的源码以后,我们惊喜地发现,这个类里面的notify方法是不是跟adapter里面的notify方法很相似,让我们来看看这个类里面的notify方法具体做了什么? 以insert为例。

代码语言:javascript
复制
public final void notifyItemInserted(int position) {
    mObservable.notifyItemRangeInserted(position, 1);
}

调用了mObservable的notifyItemRangeInserted方法,也就是我们上面分析的AdapterDataObservable的notifyItemRangeInserted方法。看看这个方法具体做了什么。

代码语言:javascript
复制
public void notifyItemRangeInserted(int positionStart, int itemCount) {
    // since onItemRangeInserted() 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).onItemRangeInserted(positionStart, itemCount);
    }
}

把它内部的mObservers遍历一遍,调用onItemRangeInserted方法,这下大家明白了吧。其实就是obeservable去通知oberser,调用onItemRangeInserted。

代码语言:javascript
复制
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
    assertNotInLayoutOrScroll(null);
    if (mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) {
        triggerUpdateProcessor();
    }
}

 void triggerUpdateProcessor() {
            if (mPostUpdatesOnAnimation && mHasFixedSize && mIsAttached) {
                ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
            } else {
                mAdapterUpdateDuringMeasure = true;
                requestLayout();
            }
        }

这是我们刚刚看过的RecyclerViewDataObserver的代码,内部具体做了什么我们不做分析了,其实就是根据不同的类型(Insert,Remove等等)注册信息并且执行动画。最终再更具注册的信息去重新绘制。

总结:

  • 1)在RecycleView的setAdapter()方法里面,它会认为注册mObservable,使其变得是可以观察的,
  • 2)接着RecyclerView内部会把自己的observer注册到observable中,
  • 3)而在adapter调用对应的notify函数的时候,observable会去通知那些注册到它这儿的observer去执行相信的动作。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年06月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档