几个概念

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

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

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

    原文地址:C#多线程之旅(1)——介绍和基本概念 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C#多线程之旅(2)——创建和开始线程 C#多线程之旅(3)——线程池 C#多线程之旅( ...

  2. TensorFlow入门,基本介绍,基本概念,计算图,pip安装,helloworld示例,实现简单的神经网络

    TensorFlow入门,基本介绍,基本概念,计算图,pip安装,helloworld示例,实现简单的神经网络

  3. 01.课程介绍 & 02.最小可行化产品MVP

    01.课程介绍 02.最小可行化产品MVP 产品开发过程 最小化和可用之间找到一个平衡点

  4. vue项目搭建介绍02

    目录 vue项目搭建介绍02 python-pycharm设置: vue创建项目分类: vue-cli构建 自定义构建 基础的vue项目目录: vue项目搭建介绍02 python-pycharm设置 ...

  5. ZooKeeper入门实战教程(一)-介绍与核心概念

    1.ZooKeeper介绍与核心概念1.1 简介ZooKeeper最为主要的使用场景,是作为分布式系统的分布式协同服务.在学习zookeeper之前,先要对分布式系统的概念有所了解,否则你将完全不知道 ...

  6. 黑马_13 Spring Boot:01.spring boot 介绍&&02.spring boot 入门

    13 Spring Boot: 01.spring boot 介绍&&02.spring boot 入门 04.spring boot 配置文件 SpringBoot基础 1.1 原有 ...

  7. 083 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 02 构造方法-带参构造方法

    083 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 02 构造方法-带参构造方法 本文知识点:构造方法-带参构造方法 说明:因为时间紧张, ...

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

    今天我们首先来说为什么要介绍这个新组件RecyclerView,因为前几天我发布了一个常用面试题ListView的复用及如何优化的文章,介绍给一些开发者,但是我看到有关的反馈说:现在都不再用listv ...

  9. maven使用.02.一些概念

    在上一篇POST中,简要的介绍了一下maven的特点,优势,安装.并建立了一个简单地Hello world工程.这一篇POST中,将主要会介绍一下Maven的一些约定. pom.xml文件 Maven ...

随机推荐

  1. ul 仿 table 循环滚动

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. 【hadoop2.6.0】利用Hadoop的 Java API

    Hadoop2.6.0的所有Java API都在 http://hadoop.apache.org/docs/r2.6.0/api/overview-summary.html 里. 下面实现一个利用J ...

  3. 控制器与xib关联(用xib布局控制器)

    IOS Xib使用——为控制器添加Xib文件 Xib文件是一个轻量级的用来描述局部界面的文件,它与StoryBoard类似,都是使用Interface Bulider工具进行编辑.但是StoryBoa ...

  4. July 1st, Week 27th Friday, 2016

    It does not do to dwell on dreams, and forget to live. 不要生活在梦里,不要沉醉于空想而疏忽了生活. Stand straightly, and ...

  5. python基础——实例属性和类属性

    python基础——实例属性和类属性 由于Python是动态语言,根据类创建的实例可以任意绑定属性. 给实例绑定属性的方法是通过实例变量,或者通过self变量: class Student(objec ...

  6. ios中通过调试来使用私有api

    转自:http://blog.csdn.net/cubepeng/article/details/11284173 OS不允许使用ios私有api,使用私有api可以获得意想不到的效果 ,同时使用私有 ...

  7. JavaWeb学习--Servlet认识

    Servlet开发 用户在浏览器中输入一个网址并回车,浏览器会向服务器发送一个HTTP请求.服务器端程序接受这个请求,并对请求进行处理,然后发送一个回应.浏览器收到回应,再把回应的内容显示出来.这种请 ...

  8. PostgreSQL中COUNT的各条件下(1亿条数据)例子

    test=# insert into tbl_time1 select generate_series(1,100000000),clock_timestamp(),now(); INSERT 0 1 ...

  9. bnuoj 24251 Counting Pair

    一道简单的规律题,画出二维表将数字分别相加可以发现很明显的对称性 题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=24251 #include< ...

  10. IT人学习方法论(一):学习方向

    07年的时候曾经讲过一节Webcast,名叫<使您成为Windows专家的一些学习习惯 >.直到最近,还经常收到听众关于这一节课反馈和心得的电子邮件,可见学习方法论是大家非常关心的问题.因 ...