RecyclerView 介绍 02 – 重要概念

来源:互联网 发布:优化生活环境的英文 编辑:程序博客网 时间:2024/03/29 08:55

几个概念

  1. RecyclerView是一个ViewGroup;
  2. LayoutManager控制RecyclerView的ChildView的布局显示,childview由Recycler提供以及管理;
  3. Recycler具有两级缓存,Scrap和RecycledViewPool,通过Detach以及Remove,对Viewholder进行转移以及状态改变;
  4. RecycledViewPool可以由多个RecyclerView共享;
  5. 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

0 0