zoukankan      html  css  js  c++  java
  • RecyclerView 介绍 02 – 重要概念

    几个概念

    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。见如下代码:

    1. View getViewForPosition(int position, boolean dryRun) {
    2.             if (position < 0 || position >= mState.getItemCount()) {
    3.                 throw new IndexOutOfBoundsException("Invalid item position " + position
    4.                         + "(" + position + "). Item count:" + mState.getItemCount());
    5.             }
    6.             boolean fromScrap = false;
    7.             ViewHolder holder = null;
    8.             // 0) If there is a changed scrap, try to find from there
    9.             if (mState.isPreLayout()) {
    10.                 holder = getChangedScrapViewForPosition(position);
    11.                 fromScrap = holder != null;
    12.             }
    13.             // 1) Find from scrap by position
    14.             if (holder == null) {
    15.                 holder = getScrapViewForPosition(position, INVALID_TYPE, dryRun);
    16.                 if (holder != null) {
    17.                     if (!validateViewHolderForOffsetPosition(holder)) {
    18.                         // recycle this scrap
    19.                         if (!dryRun) {
    20.                             // we would like to recycle this but need to make sure it is not used by
    21.                             // animation logic etc.
    22.                             holder.addFlags(ViewHolder.FLAG_INVALID);
    23.                             if (holder.isScrap()) {
    24.                                 removeDetachedView(holder.itemView, false);
    25.                                 holder.unScrap();
    26.                             } else if (holder.wasReturnedFromScrap()) {
    27.                                 holder.clearReturnedFromScrapFlag();
    28.                             }
    29.                             recycleViewHolderInternal(holder);
    30.                         }
    31.                         holder = null;
    32.                     } else {
    33.                         fromScrap = true;
    34.                     }
    35.                 }
    36.             }
    37.             if (holder == null) {
    38.                 final int offsetPosition = mAdapterHelper.findPositionOffset(position);
    39.                 if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) {
    40.                     throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item "
    41.                             + "position " + position + "(offset:" + offsetPosition + ")."
    42.                             + "state:" + mState.getItemCount());
    43.                 }
    44.  
    45.                 final int type = mAdapter.getItemViewType(offsetPosition);
    46.                 // 2) Find from scrap via stable ids, if exists
    47.                 if (mAdapter.hasStableIds()) {
    48.                     holder = getScrapViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);
    49.                     if (holder != null) {
    50.                         // update position
    51.                         holder.mPosition = offsetPosition;
    52.                         fromScrap = true;
    53.                     }
    54.                 }
    55.                 if (holder == null && mViewCacheExtension != null) {
    56.                     // We are NOT sending the offsetPosition because LayoutManager does not
    57.                     // know it.
    58.                     final View view = mViewCacheExtension
    59.                             .getViewForPositionAndType(this, position, type);
    60.                     if (view != null) {
    61.                         holder = getChildViewHolder(view);
    62.                         if (holder == null) {
    63.                             throw new IllegalArgumentException("getViewForPositionAndType returned"
    64.                                     + " a view which does not have a ViewHolder");
    65.                         } else if (holder.shouldIgnore()) {
    66.                             throw new IllegalArgumentException("getViewForPositionAndType returned"
    67.                                     + " a view that is ignored. You must call stopIgnoring before"
    68.                                     + " returning this view.");
    69.                         }
    70.                     }
    71.                 }
    72.                 if (holder == null) { // fallback to recycler
    73.                     // try recycler.
    74.                     // Head to the shared pool.
    75.                     if (DEBUG) {
    76.                         Log.d(TAG, "getViewForPosition(" + position + ") fetching from shared "
    77.                                 + "pool");
    78.                     }
    79.                     holder = getRecycledViewPool()
    80.                             .getRecycledView(mAdapter.getItemViewType(offsetPosition));
    81.                     if (holder != null) {
    82.                         holder.resetInternal();
    83.                         if (FORCE_INVALIDATE_DISPLAY_LIST) {
    84.                             invalidateDisplayListInt(holder);
    85.                         }
    86.                     }
    87.                 }
    88.                 if (holder == null) {
    89.                     holder = mAdapter.createViewHolder(RecyclerView.this,
    90.                             mAdapter.getItemViewType(offsetPosition));
    91.                     if (DEBUG) {
    92.                         Log.d(TAG, "getViewForPosition created new ViewHolder");
    93.                     }
    94.                 }
    95.             }
    96.             boolean bound = false;
    97.             if (mState.isPreLayout() && holder.isBound()) {
    98.                 // do not update unless we absolutely have to.
    99.                 holder.mPreLayoutPosition = position;
    100.             } else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
    101.                 if (DEBUG && holder.isRemoved()) {
    102.                     throw new IllegalStateException("Removed holder should be bound and it should"
    103.                             + " come here only in pre-layout. Holder: " + holder);
    104.                 }
    105.                 final int offsetPosition = mAdapterHelper.findPositionOffset(position);
    106.                 mAdapter.bindViewHolder(holder, offsetPosition);
    107.                 attachAccessibilityDelegate(holder.itemView);
    108.                 bound = true;
    109.                 if (mState.isPreLayout()) {
    110.                     holder.mPreLayoutPosition = position;
    111.                 }
    112.             }
    113.  
    114.             final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
    115.             final LayoutParams rvLayoutParams;
    116.             if (lp == null) {
    117.                 rvLayoutParams = (LayoutParams) generateDefaultLayoutParams();
    118.                 holder.itemView.setLayoutParams(rvLayoutParams);
    119.             } else if (!checkLayoutParams(lp)) {
    120.                 rvLayoutParams = (LayoutParams) generateLayoutParams(lp);
    121.                 holder.itemView.setLayoutParams(rvLayoutParams);
    122.             } else {
    123.                 rvLayoutParams = (LayoutParams) lp;
    124.             }
    125.             rvLayoutParams.mViewHolder = holder;
    126.             rvLayoutParams.mPendingInvalidate = fromScrap && bound;
    127.             return holder.itemView;
    128.         }

    关于ViewHolder

    在RecyclerView里面,view是有多重状态的,各种状态在ViewHolder里面定义。看看下面的代码:

    1. public static abstract class ViewHolder {
    2.       public final View itemView;
    3.       int mPosition = NO_POSITION;
    4.       int mOldPosition = NO_POSITION;
    5.       long mItemId = NO_ID;
    6.       int mItemViewType = INVALID_TYPE;
    7.       int mPreLayoutPosition = NO_POSITION;
    8.  
    9.       // The item that this holder is shadowing during an item change event/animation
    10.       ViewHolder mShadowedHolder = null;
    11.       // The item that is shadowing this holder during an item change event/animation
    12.       ViewHolder mShadowingHolder = null;
    13.  
    14.       /**
    15.        * This ViewHolder has been bound to a position; mPosition, mItemId and mItemViewType
    16.        * are all valid.
    17.        */
    18.       static final int FLAG_BOUND = 1 << 0;
    19.  
    20.       /**
    21.        * The data this ViewHolder's view reflects is stale and needs to be rebound
    22.        * by the adapter. mPosition and mItemId are consistent.
    23.        */
    24.       static final int FLAG_UPDATE = 1 << 1;
    25.  
    26.       /**
    27.        * This ViewHolder's data is invalid. The identity implied by mPosition and mItemId
    28.        * are not to be trusted and may no longer match the item view type.
    29.        * This ViewHolder must be fully rebound to different data.
    30.        */
    31.       static final int FLAG_INVALID = 1 << 2;
    32.  
    33.       /**
    34.        * This ViewHolder points at data that represents an item previously removed from the
    35.        * data set. Its view may still be used for things like outgoing animations.
    36.        */
    37.       static final int FLAG_REMOVED = 1 << 3;
    38.  
    39.       /**
    40.        * This ViewHolder should not be recycled. This flag is set via setIsRecyclable()
    41.        * and is intended to keep views around during animations.
    42.        */
    43.       static final int FLAG_NOT_RECYCLABLE = 1 << 4;
    44.  
    45.       /**
    46.        * This ViewHolder is returned from scrap which means we are expecting an addView call
    47.        * for this itemView. When returned from scrap, ViewHolder stays in the scrap list until
    48.        * the end of the layout pass and then recycled by RecyclerView if it is not added back to
    49.        * the RecyclerView.
    50.        */
    51.       static final int FLAG_RETURNED_FROM_SCRAP = 1 << 5;
    52.  
    53.       /**
    54.        * This ViewHolder's contents have changed. This flag is used as an indication that
    55.        * change animations may be used, if supported by the ItemAnimator.
    56.        */
    57.       static final int FLAG_CHANGED = 1 << 6;
    58.  
    59.       /**
    60.        * This ViewHolder is fully managed by the LayoutManager. We do not scrap, recycle or remove
    61.        * it unless LayoutManager is replaced.
    62.        * It is still fully visible to the LayoutManager.
    63.        */
    64.       static final int FLAG_IGNORE = 1 << 7;

    ------EOF----------

  • 相关阅读:
    hdu 4027 Can you answer these queries?
    hdu 4041 Eliminate Witches!
    hdu 4036 Rolling Hongshu
    pku 2828 Buy Tickets
    hdu 4016 Magic Bitwise And Operation
    pku2886 Who Gets the Most Candies?(线段树+反素数打表)
    hdu 4039 The Social Network
    hdu 4023 Game
    苹果官方指南:Cocoa框架(2)(非原创)
    cocos2d 中 CCNode and CCAction
  • 原文地址:https://www.cnblogs.com/halzhang/p/4445145.html
Copyright © 2011-2022 走看看