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----------

时间: 2024-10-11 13:26:51

RecyclerView 介绍 02 – 重要概念的相关文章

JavaOO视频-04【基本数据类型介绍02、数据类型转换】

转载请标明,http://www.gxabase.com视频内容:此节视频会接着给大家讲基本数据类型的介绍,包括:浮点型.字符型.布尔型.然后再为大家介绍学习八大基本数据类型必须掌握的数据类型转换这一知识点. JavaOO视频-04[基本数据类型介绍02.数据类型转换],布布扣,bubuko.com

C#多线程之旅(1)——介绍和基本概念

原文目录C#多线程之旅(1)——介绍和基本概念 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C#多线程之旅(2)——创建和开始线程 C#多线程之旅(3)——线程池 C#多线程之旅(4)——同步本质 ...... C#多线程之旅(1)——介绍和基本概念 一.多线程介绍 C#通过多线程支持并行执行的代码.一个线程是一个独立执行的路径,可以同时与其他线程一起运行.一个C#客户端程序(Console,WPF,Winows Forms)开始于一个单独的线程,该线程由CLR和操作系统自动地

RecyclerView 介绍 基本使用

介绍 文档位置:https://developer.android.google.cn/reference/android/support/v7/widget/RecyclerView.html A flexible view for providing a limited window into a large data set. RecylerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能,这一点从它的名字rec

Android新组件RecyclerView介绍,其效率更好

今天我们首先来说为什么要介绍这个新组件RecyclerView,因为前几天我发布了一个常用面试题ListView的复用及如何优化的文章,介绍给一些开发者,但是我看到有关的反馈说:现在都不再用listview了,代替的是RecyclerView,确实是,但是用的毕竟是少数,所以可能很多人对于这个组件不是很了解,那么我们就来介绍一下吧! 1.什么是RecyclerView RecyclerView 是 android-support-v7-21 版本中新增的一个 Widgets,官方对于它的介绍则是

Kubernetes介绍及基本概念

kubernetes介绍 Kubernetes是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,Kubernetes也叫K8S.K8S是Google内部一个叫Borg的容器集群管理系统衍生出来的,Borg已经在Google大规模生产运行十年之久.K8S主要用于自动化部署.扩展和管理容器应用,提供了资源调度.部署管理.服务发现.扩容缩容.监控等一整套功能.2015年7月,Kubernetes v1.0正式发布,截止到2018年1月27日最新稳定版本是v1.9.2.Kube

GStreamer基础教程02 - 基本概念

摘要 在 Gstreamer基础教程01 - Hello World中,我们介绍了如何快速的通过一个字符串创建一个简单的pipeline.为了能够更好的控制pipline中的element,我们需要单独创建element,然后再构造pipeline,下面将介绍GStreamer的一些基本概念并展示pipeline的另一种构造方式. 基本概念 Element 我们知道element是构建GStreamer pipeline的基础,element在框架中的类型为GstElement,所有GStrea

volle介绍02

---------------------------------------------------------------------------- 转载:http://blog.csdn.net/crazy__chen/article/details/46483329 ---------------------------------------------------------------------------- Volley是一款由Google 推出的 Android 异步网络请求

RecyclerView 介绍01

RecyclerView是Android support v7里面是一个自定义控件.用来显示大量数据集合.类似ListView和GridView这两个控件,RecyclerView同样可以实现,甚至更好. 以前我们在实现ListView和GridView的时候,都会定义一个ViewHolder用于优化UI性能[详见],RecycleView的实现,已经是自带ViewHolder的实现.请看示例. 实现Adapter,定义每个Item的布局UI和数据. ? public class MyRecyc

02 基本概念

======自我整理====== ### Docker 包括三个基本概念 > 1.镜像(Image) > 2.容器(Container) > 3.仓库(Repository) 理解了这三个概念,就理解了 Docker 的整个生命周期 #### 1.镜像 Docker 镜像就是一个只读的模板. 例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序. 镜像可以用来创建 Docker 容器. Docker 提供了一个很简单的机制来创