RecyclerView 介紹 02 – 重要概念
幾個概念
- 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
相關文章
- RecyclerView 介紹 01View
- Spark概念介紹Spark
- JavaEE概念介紹Java
- Oracle RAC 概念介紹Oracle
- TypeScript Mixins 概念介紹TypeScript
- Vue 關鍵概念介紹Vue
- javascript閉包概念介紹JavaScript
- 嵌入式概念介紹
- Android新元件RecyclerView介紹,其效率更好Android元件View
- Oracle cluster table(1)_概念介紹Oracle
- Nginx 教程:基本概念介紹Nginx
- mysql中SQL的概念介紹MySql
- Redux的簡單概念介紹Redux
- Django重要元件之Auth模組介紹Django元件
- 人工智慧重要會議介紹人工智慧
- Java之Spring Cloud概念介紹JavaSpringCloud
- javascript遞迴概念簡單介紹JavaScript遞迴
- 數字簽名相關概念介紹
- oracle goldengate 相關概念介紹OracleGo
- Spark Streaming基礎概念介紹Spark
- 網頁抓取的重要性介紹網頁
- 數值分析1 - 誤差概念介紹
- 移動OA軟體重要功能介紹
- Perl的一些重要模組使用介紹
- 《AOP挖掘記》概念介紹及原理初探(一)
- Spring基礎只是—AOP的概念介紹Spring
- web應用防火牆概念及功能介紹!Web防火牆
- Quartz.Net 主要概念介紹和吐槽quartz
- javascript中的閉包概念簡單介紹JavaScript
- 介紹ORACLE DATA GUARD——DATA GUARD概念和管理Oracle
- 一些重要 Docker 命令的簡單介紹Docker
- RAC重要概念和原理
- 微服務架構 SpringCloud - 元件和概念介紹微服務架構SpringGCCloud元件
- 介紹一下Spring Cloud Stream主要概念SpringCloud
- Java集合框架的概念以及常用介面的介紹Java框架
- 大資料以及Hadoop相關概念介紹大資料Hadoop
- 系統SDK介紹-02
- 微課sql最佳化(1)、基礎概念介紹SQL