RecyclerView 介绍 02 – 重要概念
2015-12-04 10:52
183 查看
几个概念
RecyclerView是一个ViewGroup;
LayoutManager控制RecyclerView的ChildView的布局显示,childview由Recycler提供以及管理;
Recycler具有两级缓存,Scrap和RecycledViewPool,通过Detach以及Remove,对Viewholder进行转移以及状态改变;
RecycledViewPool可以由多个RecyclerView共享;
ViewHolder具有多种状态标记;
关于Recycler
Scrap中的ViewHolder,不用通过Adapter重新处理,只需要attach后回到LayoutManager就可以重用。
RecycledViewPool中的ViewHolder,数据往往是错误的,则需要通过Adapter重新绑定正确的数据后在回到LayoutManager。
当LayoutManager需要一个新的View时,Recycler会行检查scrap中是否有合适的ViewHolder,如果有直接返回给LayoutManager使用;如果没有,就需要从Pool里面寻找,然后右Adapter重新绑定数据后,返回到LayoutManager;如果pool还是没有,就需要由Adapter创建一个新的Viewholder。见如下代码:
关于ViewHolder
在RecyclerView里面,view是有多重状态的,各种状态在ViewHolder里面定义。看看下面的代码:
------EOF----------
转自:http://www.cnblogs.com/halzhang/p/4445145.html
RecyclerView是一个ViewGroup;
LayoutManager控制RecyclerView的ChildView的布局显示,childview由Recycler提供以及管理;
Recycler具有两级缓存,Scrap和RecycledViewPool,通过Detach以及Remove,对Viewholder进行转移以及状态改变;
RecycledViewPool可以由多个RecyclerView共享;
ViewHolder具有多种状态标记;
关于Recycler
Scrap中的ViewHolder,不用通过Adapter重新处理,只需要attach后回到LayoutManager就可以重用。
RecycledViewPool中的ViewHolder,数据往往是错误的,则需要通过Adapter重新绑定正确的数据后在回到LayoutManager。
当LayoutManager需要一个新的View时,Recycler会行检查scrap中是否有合适的ViewHolder,如果有直接返回给LayoutManager使用;如果没有,就需要从Pool里面寻找,然后右Adapter重新绑定数据后,返回到LayoutManager;如果pool还是没有,就需要由Adapter创建一个新的Viewholder。见如下代码:
View getViewForPosition(int position, boolean dryRun) { if (position < 0 || position >= mState.getItemCount()) { throw new IndexOutOfBoundsException("Invalid item position " + position + "(" + position + "). Item count:" + mState.getItemCount()); } boolean fromScrap = false; ViewHolder holder = null; // 0) If there is a changed scrap, try to find from there if (mState.isPreLayout()) { holder = getChangedScrapViewForPosition(position); fromScrap = holder != null; } // 1) Find from scrap by position if (holder == null) { holder = getScrapViewForPosition(position, INVALID_TYPE, dryRun); if (holder != null) { if (!validateViewHolderForOffsetPosition(holder)) { // recycle this scrap if (!dryRun) { // we would like to recycle this but need to make sure it is not used by // animation logic etc. holder.addFlags(ViewHolder.FLAG_INVALID); if (holder.isScrap()) { removeDetachedView(holder.itemView, false); holder.unScrap(); } else if (holder.wasReturnedFromScrap()) { holder.clearReturnedFromScrapFlag(); } recycleViewHolderInternal(holder); } holder = null; } else { fromScrap = true; } } } if (holder == null) { final int offsetPosition = mAdapterHelper.findPositionOffset(position); if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) { throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item " + "position " + position + "(offset:" + offsetPosition + ")." + "state:" + mState.getItemCount()); } final int type = mAdapter.getItemViewType(offsetPosition); // 2) Find from scrap via stable ids, if exists if (mAdapter.hasStableIds()) { holder = getScrapViewForId(mAdapter.getItemId(offsetPosition), type, dryRun); if (holder != null) { // update position holder.mPosition = offsetPosition; fromScrap = true; } } if (holder == null && mViewCacheExtension != null) { // We are NOT sending the offsetPosition because LayoutManager does not // know it. final View view = mViewCacheExtension .getViewForPositionAndType(this, position, type); if (view != null) { holder = getChildViewHolder(view); if (holder == null) { throw new IllegalArgumentException("getViewForPositionAndType returned" + " a view which does not have a ViewHolder"); } else if (holder.shouldIgnore()) { throw new IllegalArgumentException("getViewForPositionAndType returned" + " a view that is ignored. You must call stopIgnoring before" + " returning this view."); } } } if (holder == null) { // fallback to recycler // try recycler. // Head to the shared pool. if (DEBUG) { Log.d(TAG, "getViewForPosition(" + position + ") fetching from shared " + "pool"); } holder = getRecycledViewPool() .getRecycledView(mAdapter.getItemViewType(offsetPosition)); if (holder != null) { holder.resetInternal(); if (FORCE_INVALIDATE_DISPLAY_LIST) { invalidateDisplayListInt(holder); } } } if (holder == null) { holder = mAdapter.createViewHolder(RecyclerView.this, mAdapter.getItemViewType(offsetPosition)); if (DEBUG) { Log.d(TAG, "getViewForPosition created new ViewHolder"); } } } boolean bound = false; if (mState.isPreLayout() && holder.isBound()) { // do not update unless we absolutely have to. holder.mPreLayoutPosition = position; } else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) { if (DEBUG && holder.isRemoved()) { throw new IllegalStateException("Removed holder should be bound and it should" + " come here only in pre-layout. Holder: " + holder); } final int offsetPosition = mAdapterHelper.findPositionOffset(position); mAdapter.bindViewHolder(holder, offsetPosition); attachAccessibilityDelegate(holder.itemView); bound = true; if (mState.isPreLayout()) { holder.mPreLayoutPosition = position; } } final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); final LayoutParams rvLayoutParams; if (lp == null) { rvLayoutParams = (LayoutParams) generateDefaultLayoutParams(); holder.itemView.setLayoutParams(rvLayoutParams); } else if (!checkLayoutParams(lp)) { rvLayoutParams = (LayoutParams) generateLayoutParams(lp); holder.itemView.setLayoutParams(rvLayoutParams); } else { rvLayoutParams = (LayoutParams) lp; } rvLayoutParams.mViewHolder = holder; rvLayoutParams.mPendingInvalidate = fromScrap && bound; return holder.itemView; }
关于ViewHolder
在RecyclerView里面,view是有多重状态的,各种状态在ViewHolder里面定义。看看下面的代码:
public static abstract class ViewHolder { public final View itemView; int mPosition = NO_POSITION; int mOldPosition = NO_POSITION; long mItemId = NO_ID; int mItemViewType = INVALID_TYPE; int mPreLayoutPosition = NO_POSITION; // The item that this holder is shadowing during an item change event/animation ViewHolder mShadowedHolder = null; // The item that is shadowing this holder during an item change event/animation ViewHolder mShadowingHolder = null; /** * This ViewHolder has been bound to a position; mPosition, mItemId and mItemViewType * are all valid. */ static final int FLAG_BOUND = 1 << 0; /** * The data this ViewHolder's view reflects is stale and needs to be rebound * by the adapter. mPosition and mItemId are consistent. */ static final int FLAG_UPDATE = 1 << 1; /** * This ViewHolder's data is invalid. The identity implied by mPosition and mItemId * are not to be trusted and may no longer match the item view type. * This ViewHolder must be fully rebound to different data. */ static final int FLAG_INVALID = 1 << 2; /** * This ViewHolder points at data that represents an item previously removed from the * data set. Its view may still be used for things like outgoing animations. */ static final int FLAG_REMOVED = 1 << 3; /** * This ViewHolder should not be recycled. This flag is set via setIsRecyclable() * and is intended to keep views around during animations. */ static final int FLAG_NOT_RECYCLABLE = 1 << 4; /** * This ViewHolder is returned from scrap which means we are expecting an addView call * for this itemView. When returned from scrap, ViewHolder stays in the scrap list until * the end of the layout pass and then recycled by RecyclerView if it is not added back to * the RecyclerView. */ static final int FLAG_RETURNED_FROM_SCRAP = 1 << 5; /** * This ViewHolder's contents have changed. This flag is used as an indication that * change animations may be used, if supported by the ItemAnimator. */ static final int FLAG_CHANGED = 1 << 6; /** * This ViewHolder is fully managed by the LayoutManager. We do not scrap, recycle or remove * it unless LayoutManager is replaced. * It is still fully visible to the LayoutManager. */ static final int FLAG_IGNORE = 1 << 7;
------EOF----------
转自:http://www.cnblogs.com/halzhang/p/4445145.html
相关文章推荐
- Android中的动态加载机制(折腾版)
- 早该知道的 7 个JavaScript 技巧[转]
- 后台管理界面-- 管理员管理[3]
- sencha touch CMD 6.0 创建 app
- 作业(1)
- 剑指offer9 变态跳台阶
- 如何成为好的程序员
- What are TCHAR, WCHAR, LPSTR, LPWSTR, LPCTSTR (etc.)?
- Day 4:PredictionIO——如何创建一个博客推荐器
- web.xml 中的listener、 filter、servlet 加载顺序及其详解
- 【风马一族_C】进制转化
- MongoDB安装
- git切换远程分支
- Linux中设置服务自启动的三种方式
- 移植ok6410 2.6内核
- Cpp--改造多重继承
- 设计并实现同时支持多种视频格式的流媒体点播系统
- 嵌入式Linux网络编程(一)
- gdb使用
- Java解惑