Android | 再探 RecyclerView 之名词解析


浏览本文前推荐先阅读 Android入门(九)| 滚动控件 ListView 与 RecyclerView

Adapter、ViewHolder

Adapter: A subclass of RecyclerView.Adapter responsible for providing views that represent items in a data set.

  • 翻译:RecyclerView.Adapter 的子类。Adapter (适配器) 负责提供表示 data set(数据集) 中 items(子项) 的 views(视图)。

  • 解析:RecyclerView 只是一个 ViewGroup,它只认识 View ,不清楚构成 前端界面View 的 后端Data数据的具体结构。因此,RecyclerView 需要一个 AdapterData 转换为 RecyclerView 认识的 ViewHolder

  • ViewHolder:view 进行操作,在 ViewHolder 中会将 view 中的各个控件实例化,然后进行管理,如:设置控件的点击事件等。


child view

RecyclerView滚动控件 中的 最小子元素,比如对于布局方式为 LinearLayout(线性布局) 的 RecyclerView 来说,child view(子视图) 就是每一行。

我个人理解为 RecyclerView 是由 data set 的所有数据构建而成的,而每个 child view 都是由某个 data item(数据子项) 构建而成的。


LayoutManager

虽然 Adapter 已经将 data set 转换为了 views,但是以怎样的布局显示这些 views 也是一个问题。因此 RecyclerView 委托 LayoutManager 负责 view 布局的显示管理。有多种布局方式供选择,如:线性布局、网格布局等。

PS:LayoutManager 只负责将 view 呈现在 Recycle 中,并不直接负责对 view 的管理,view 的管理由下面的 Recycler 负责。

扫描二维码关注公众号,回复: 15056304 查看本文章

Recycler

管理不在前台的 View,对 View 进行缓存,以便后续重用,避免每次都需要加载 view,显著提高性能。LayoutManager 在需要 View 的时候会向 Recycler 进行索取,当 LayoutManager 不需要 View (试图滑出)的时候,就直接将废弃的 View 丢给 Recycler


Scrap

在加载布局期间已进入 临时分离(temporarily detached) 状态的子视图。 Scrap views 可以在不与 parent RecyclerView 完全分离(fully detached) 的情况下重用。 重用时需要做进一步判定是否需要修改 scrap views

  • 如果不需要 rebinding重新绑定 则不需要修改。
  • 如果该 view 被视为 dirty,则由 适配器Adapter 进行修改。

Dirty

在显示之前必须由 适配器 重新绑定rebound子视图child view


Index

调用 ViewGroup.getChildAt() 时使用的参数,已经添加到 RecyclerView 中的 子view 的索引。 与 Position 形成对比,Position 是数据的位置,Index 是视图的位置。


Position

Position: The position of a data item within an Adapter.

  • 适配器中 data item(数据子项) 的位置。

Position 从大的方向可以分为两种情况:

  1. 方法 onBindViewHolder() 中的参数 position
  2. 通过 ViewHoldergetLayoutPosition()/getAdapterPosition() 方法得到的 layout position/adapter position

对于第一种 positon,我们通常使用它来得到子视图,举个例子:

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    
    
	// 通过 position 获取 DataSet 数据集(如数组等)中对应的子项 Date
	Date date = DataSet.get(position);
}

对于第二种

layout position 和 adapter position

ListView 不同, RecyclerView 将 跟踪 Adapter 的工作从 RecyclerView.LayoutManager 中抽离,交给 RecyclerView.Adapter 类。ListView 是没有 “ListView.Adapter” 的,ListView 中需要用到适配器的时候,都是自定义一个 BaseAdapter类 的子类,而 RecyclerView 已经为开发者封装好了 RecyclerView.Adapter ,如此一来 RecyclerView 便能够在更新布局期间对 data set(数据集)进行批处理(等待数据修改完成再传递给布局,此等待时间小于 16 毫秒)。这可以将 LayoutManager 从跟踪 Adapter 的工作中解脱出来,而去负责 calculate animations(更新界面)的工作。这有助于提高性能,因为所有 view bindings(视图绑定) 都同时发生,并且避免了不必要的绑定。

不过这种抽象方式导致了在 RecyclerView 中有两种与 位置 相关的方法:

  • layout position: 在最近一次布局更新后 view item 在布局中的位置,这个位置是站在 LayoutManager 的角度得到的 view 的位置,也是布局更新后用户直观看到的布局。通过 getLayoutPosition() 得到。
  • adapter position: ViewHolder item 在适配器中的位置,这是站在 Adapter 的角度得到的 ViewHolder 所在的位置,通常是用户单击某个 ViewHolder item 时,询问 Adapter 得到的。通过 getAdapterPosition() 得到。

当适配器内容改变时,并且调用 adapter.notify*方法 从 RecyclerView 请求一个新的布局。从那一刻起,新布局更新完成(此时间小于 16 毫秒),两个 position 可能不匹配,因为布局还没有反映适配器的变化。除此之外,这两个 position 在大多数时候是相等的。

getAdapterPosition() 使用时的注意事项:

  • 由于调用 notifyDataSetChanged() 会使所有内容无效,因此 RecyclerView 在更新下一个布局之前不知道 ViewHolderadapter position。在这种情况下,getAdapterPosition() 将返回 RecyclerView#NO_POSITION( -1)

  • 但是假设调用了 notifyItemInserted(0) ,先前 adapter position = 0ViewHolder 调用 getAdapterPosition() 将立即返回 adapter position = 1。因此,只要是对 granular (最小粒度,指单元子项)调用 notify events (应该指的是 notifyItem* 方法),那么即使布局尚未更新完成,也能立刻获得 adapter position

  • 如果用户点击时 getAdapterPosition() 返回 NO_POSITION,那么最好忽略那个点击,因为不知道用户点击了什么(除非有一些其他的机制能够确认被点击的是什么,例如用于查找单元子项的稳定ID)。


四级缓存

缓存级别 详细描述
一级缓存 mAttachedScrap/mChangedScrap 缓存屏幕可见范围的 ViewHolder
二级缓存 mCachedViews 按 child View 的 position 或 id 缓存滑动时即将与 RecyclerView 分离的 ViewHolder。
三级缓存 mViewCacheExtension 开发者自行实现的缓存。
四级缓存 mRecyclerPool ViewHolder缓存池,本质上是一个 android.util.SparseArray,其中 key 是 ViewType(int类型),value 存放的是 ArrayList< ViewHolder> ,默认每个 ArrayList 中最多存放5个 ViewHolder。

猜你喜欢

转载自blog.csdn.net/Jormungand_V/article/details/124950068
今日推荐