关于RecyclerView的Adapter的notifyItemInserted()的一些分析
来源:互联网 发布:淘宝怎么取消匿名 编辑:程序博客网 时间:2024/06/05 12:40
转载请注明原博客地址:http://blog.csdn.net/gdutxiaoxu/article/details/51698261
本篇文章主要是针对RecyclerView的Adapter的notifyItemInserted()等方法进行分析,不涉及过多的源码分析,毕竟RecyclerView的代码有11037行,个人水平有限。
我们知道RecyclerView的Adapter与ListView的Adapter相比较,主要有一下的几点不同
1)在ListView的Adapter里面,holder这个类是需要我们自己实现的,同时需要我们判断convertView是否为空,典型的做法如下:
@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,主要多了这几个方法
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)
public final void notifyItemInserted(int position) { mObservable.notifyItemRangeInserted(position, 1);}
public static abstract class Adapter<VH extends ViewHolder> { private final AdapterDataObservable mObservable = new AdapterDataObservable(); - - - -}
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()这个方法
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 这个类
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为例。
public final void notifyItemInserted(int position) { mObservable.notifyItemRangeInserted(position, 1);}
调用了mObservable的notifyItemRangeInserted方法,也就是我们上面分析的AdapterDataObservable的notifyItemRangeInserted方法。看看这个方法具体做了什么。
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。
@Overridepublic 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去执行相信的动作。
- 关于RecyclerView的Adapter的notifyItemInserted()的一些分析
- RecyclerView.Adapter关于notifyItemInserted等数据错位问题
- 关于RecyclerView的Adapter封装
- RecyclerView万能的Adapter
- RecyclerView的万能Adapter
- RecyclerView.Adapter的封装
- RecyclerView.Adapter的实现
- RecyclerView+RecyclerView.Adapter+RecyclerView.ViewHolder的使用
- 关于RecyclerView的一些概念
- 关于RecyclerView的一些笔记
- 关于Recyclerview的一些常见问题
- RecyclerView 的 RecyclerView.Adapter 通用版的实现
- RecyclerView的Adapter的抽取
- 关于listview的adapter的一些思考
- Recyclerview的一些个人理解与使用(一)adapter的简单封装
- RecyclerView的Adapter最佳实战
- Recyclerview Adapter 的简单封装
- RecyclerView的Adapter万能适配包
- Win7允许/禁用 PING命令
- poj 1185(状态压缩dp)
- LUA string库详解
- 外部数据库的引入
- windows2003服务器mysql每天定时备份
- 关于RecyclerView的Adapter的notifyItemInserted()的一些分析
- Linux shell 简单使用
- ASP网站实例教程:[1]IIS安装配置(win7 asp)-心得记录
- 李铁映
- git强制更新本地代码,忽略掉本地任何修改
- Hash算法的使用
- Linux less命令分页显示
- eclipse常用快捷键
- PAT 1053 Path of Equal Weight