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----------
RecyclerView 介绍 02 – 重要概念的更多相关文章
- C#多线程之旅(1)——介绍和基本概念
原文地址:C#多线程之旅(1)——介绍和基本概念 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C#多线程之旅(2)——创建和开始线程 C#多线程之旅(3)——线程池 C#多线程之旅( ...
- TensorFlow入门,基本介绍,基本概念,计算图,pip安装,helloworld示例,实现简单的神经网络
TensorFlow入门,基本介绍,基本概念,计算图,pip安装,helloworld示例,实现简单的神经网络
- 01.课程介绍 & 02.最小可行化产品MVP
01.课程介绍 02.最小可行化产品MVP 产品开发过程 最小化和可用之间找到一个平衡点
- vue项目搭建介绍02
目录 vue项目搭建介绍02 python-pycharm设置: vue创建项目分类: vue-cli构建 自定义构建 基础的vue项目目录: vue项目搭建介绍02 python-pycharm设置 ...
- ZooKeeper入门实战教程(一)-介绍与核心概念
1.ZooKeeper介绍与核心概念1.1 简介ZooKeeper最为主要的使用场景,是作为分布式系统的分布式协同服务.在学习zookeeper之前,先要对分布式系统的概念有所了解,否则你将完全不知道 ...
- 黑马_13 Spring Boot:01.spring boot 介绍&&02.spring boot 入门
13 Spring Boot: 01.spring boot 介绍&&02.spring boot 入门 04.spring boot 配置文件 SpringBoot基础 1.1 原有 ...
- 083 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 02 构造方法-带参构造方法
083 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 02 构造方法-带参构造方法 本文知识点:构造方法-带参构造方法 说明:因为时间紧张, ...
- Android新组件RecyclerView介绍,其效率更好
今天我们首先来说为什么要介绍这个新组件RecyclerView,因为前几天我发布了一个常用面试题ListView的复用及如何优化的文章,介绍给一些开发者,但是我看到有关的反馈说:现在都不再用listv ...
- maven使用.02.一些概念
在上一篇POST中,简要的介绍了一下maven的特点,优势,安装.并建立了一个简单地Hello world工程.这一篇POST中,将主要会介绍一下Maven的一些约定. pom.xml文件 Maven ...
随机推荐
- ul 仿 table 循环滚动
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 【hadoop2.6.0】利用Hadoop的 Java API
Hadoop2.6.0的所有Java API都在 http://hadoop.apache.org/docs/r2.6.0/api/overview-summary.html 里. 下面实现一个利用J ...
- 控制器与xib关联(用xib布局控制器)
IOS Xib使用——为控制器添加Xib文件 Xib文件是一个轻量级的用来描述局部界面的文件,它与StoryBoard类似,都是使用Interface Bulider工具进行编辑.但是StoryBoa ...
- July 1st, Week 27th Friday, 2016
It does not do to dwell on dreams, and forget to live. 不要生活在梦里,不要沉醉于空想而疏忽了生活. Stand straightly, and ...
- python基础——实例属性和类属性
python基础——实例属性和类属性 由于Python是动态语言,根据类创建的实例可以任意绑定属性. 给实例绑定属性的方法是通过实例变量,或者通过self变量: class Student(objec ...
- ios中通过调试来使用私有api
转自:http://blog.csdn.net/cubepeng/article/details/11284173 OS不允许使用ios私有api,使用私有api可以获得意想不到的效果 ,同时使用私有 ...
- JavaWeb学习--Servlet认识
Servlet开发 用户在浏览器中输入一个网址并回车,浏览器会向服务器发送一个HTTP请求.服务器端程序接受这个请求,并对请求进行处理,然后发送一个回应.浏览器收到回应,再把回应的内容显示出来.这种请 ...
- PostgreSQL中COUNT的各条件下(1亿条数据)例子
test=# insert into tbl_time1 select generate_series(1,100000000),clock_timestamp(),now(); INSERT 0 1 ...
- bnuoj 24251 Counting Pair
一道简单的规律题,画出二维表将数字分别相加可以发现很明显的对称性 题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=24251 #include< ...
- IT人学习方法论(一):学习方向
07年的时候曾经讲过一节Webcast,名叫<使您成为Windows专家的一些学习习惯 >.直到最近,还经常收到听众关于这一节课反馈和心得的电子邮件,可见学习方法论是大家非常关心的问题.因 ...