android RecyclerView 详解
一、RecyclerView 是什么
RecyclerView 是 Android 官方推荐用于展示大量可滚动数据列表的控件,位于 androidx.recyclerview.widget 包中。它通过视图复用机制高效管理列表项,解决了 ListView 的性能瓶颈。
二、核心架构与组件
RecyclerView 采用组合式设计,通过多个独立组件协同工作:
┌─────────────────────────────────────┐
│ RecyclerView │
│ ┌─────────────────────────────┐ │
│ │ LayoutManager │ │ ← 负责布局排列(线性/网格/瀑布流)
│ │ (Linear/Grid/Staggered) │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ Adapter │ │ ← 数据 ↔ 视图的绑定桥梁
│ │ (数据提供 + View创建) │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ ViewHolder │ │ ← 缓存视图引用,避免 findViewById
│ │ (itemView + 子视图缓存) │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ ItemDecoration │ │ ← 分割线、间距、高亮等装饰
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ ItemAnimator │ │ ← 增删改动画(默认支持)
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
1. Adapter(适配器)
负责创建 ViewHolder 和绑定数据到视图。
kotlin
class MyAdapter(private val dataList: List<String>) :
RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
// 创建新的 ViewHolder(仅当没有可复用的时调用)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_layout, parent, false)
return MyViewHolder(view)
}
// 将数据绑定到 ViewHolder
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(dataList[position])
}
override fun getItemCount(): Int = dataList.size
// ViewHolder:缓存子视图引用
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textView: TextView = itemView.findViewById(R.id.tv_text)
fun bind(data: String) {
textView.text = data
}
}
}
2. LayoutManager(布局管理器)
决定列表项的排列方式:
表格
| 类型 | 类名 | 特点 |
|---|---|---|
| 线性 | LinearLayoutManager | 垂直/水平单行排列,类似 ListView |
| 网格 | GridLayoutManager | 多列网格,支持 spanSizeLookup 实现不规则跨度 |
| 瀑布流 | StaggeredGridLayoutManager | 交错网格,适合高度不一致的内容(如图片墙) |
| 自定义 | 继承 LayoutManager | 完全自定义布局逻辑 |
kotlin
// 垂直线性布局
recyclerView.layoutManager = LinearLayoutManager(context)
// 2列网格
recyclerView.layoutManager = GridLayoutManager(context, 2)
// 垂直瀑布流,2列
recyclerView.layoutManager = StaggeredGridLayoutManager(2, RecyclerView.VERTICAL)
3. ViewHolder(视图持有者)
-
通过
itemView持有列表项的根视图 -
缓存子视图引用,避免每次绑定都调用昂贵的
findViewById -
必须使用静态内部类或独立类,防止内存泄漏
4. ItemDecoration(装饰)
用于绘制分割线、间距、悬浮头等:
kotlin
// 添加默认分割线
recyclerView.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
// 自定义间距
class SpaceDecoration(private val space: Int) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
) {
outRect.set(space, space, space, space)
}
}
5. ItemAnimator(动画)
默认使用 DefaultItemAnimator,支持增删改动画:
kotlin
// 自定义动画时长
(recyclerView.itemAnimator as? SimpleItemAnimator)?.apply {
addDuration = 300
removeDuration = 300
}
三、基本使用流程
kotlin
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
// 1. 设置 LayoutManager
recyclerView.layoutManager = LinearLayoutManager(this)
// 2. 设置 Adapter
val adapter = MyAdapter(getData())
recyclerView.adapter = adapter
// 3. (可选)设置固定高度优化
recyclerView.setHasFixedSize(true)
// 4. (可选)添加装饰和动画
recyclerView.addItemDecoration(SpaceDecoration(16))
}
}
四、高级用法
1. 使用 ListAdapter + DiffUtil(推荐)
ListAdapter 内置 DiffUtil,自动计算数据差异并刷新:
kotlin
class MyListAdapter : ListAdapter<String, MyListAdapter.ViewHolder>(DiffCallback()) {
class DiffCallback : DiffUtil.ItemCallback<String>() {
override fun areItemsTheSame(old: String, new: String): Boolean {
return old == new // 唯一标识判断
}
override fun areContentsTheSame(old: String, new: String): Boolean {
return old == new // 内容是否相同
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// ...
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item: String) { /* ... */ }
}
}
// 使用:提交新列表,自动计算差异并刷新
adapter.submitList(newList)
2. 多类型布局(Multiple View Types)
通过 getItemViewType() 实现聊天界面、信息流等复杂场景:
kotlin
class ChatAdapter(private val messages: List<Message>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
const val TYPE_SENT = 1
const val TYPE_RECEIVED = 2
}
override fun getItemViewType(position: Int): Int {
return if (messages[position].isSent) TYPE_SENT else TYPE_RECEIVED
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
TYPE_SENT -> SentViewHolder(...)
else -> ReceivedViewHolder(...)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is SentViewHolder -> holder.bind(messages[position])
is ReceivedViewHolder -> holder.bind(messages[position])
}
}
}
3. 拖拽排序与滑动删除
通过 ItemTouchHelper 实现:
kotlin
val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN, // 拖拽方向
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT // 滑动删除方向
) {
override fun onMove(
recyclerView: RecyclerView,
from: RecyclerView.ViewHolder,
to: RecyclerView.ViewHolder
): Boolean {
val fromPos = from.adapterPosition
val toPos = to.adapterPosition
Collections.swap(dataList, fromPos, toPos)
adapter.notifyItemMoved(fromPos, toPos)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val pos = viewHolder.adapterPosition
dataList.removeAt(pos)
adapter.notifyItemRemoved(pos)
}
})
itemTouchHelper.attachToRecyclerView(recyclerView)
4. 分页加载
配合 Paging 3 库实现无限滚动:
kotlin
val pagingAdapter = MyPagingAdapter()
recyclerView.adapter = pagingAdapter
lifecycleScope.launch {
viewModel.pagingDataFlow.collectLatest { pagingData ->
pagingAdapter.submitData(pagingData)
}
}
五、性能优化
表格
| 优化手段 | 说明 |
|---|---|
setHasFixedSize(true) | 如果 Adapter 内容变化不影响 RecyclerView 大小,避免额外布局计算 |
| ViewHolder 模式 | 必须正确使用,缓存 findViewById 结果 |
避免在 onBindViewHolder 中创建对象 | 如 OnClickListener 应在 onCreateViewHolder 中设置 |
使用 DiffUtil / ListAdapter | 局部刷新,避免 notifyDataSetChanged() 全局重绘 |
| 图片加载优化 | 使用 Glide/Coil,配合 RecyclerView 滚动时暂停加载 |
| 嵌套 RecyclerView 复用 | 使用 setRecycledViewPool() 共享 ViewHolder 池 |
| 异步布局计算 | AsyncLayoutInflater 预加载布局 |
| 预加载 | GapWorker 默认预加载,或通过 LayoutManager 自定义 |
常见反模式 ❌
kotlin
// ❌ 错误:在 onBind 中设置点击监听(每次绑定都创建新对象)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.setOnClickListener { /* ... */ } // 不要这样做!
}
// ✅ 正确:在 onCreateViewHolder 中设置,通过 adapterPosition 获取位置
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val holder = ViewHolder(...)
holder.itemView.setOnClickListener {
val pos = holder.adapterPosition
if (pos != RecyclerView.NO_POSITION) {
onItemClick(pos)
}
}
return holder
}
六、RecyclerView vs ListView
表格
| 特性 | ListView | RecyclerView |
|---|---|---|
| ViewHolder | 官方推荐但非强制 | 强制使用 |
| 布局类型 | 仅垂直列表 | 线性/网格/瀑布流/自定义 |
| 动画 | 无内置 | 内置 ItemAnimator |
| 分割线 | divider 属性 | ItemDecoration 灵活定制 |
| 点击监听 | setOnItemClickListener | 需在 ViewHolder 中手动设置 |
| 局部刷新 | 不支持 | notifyItemXXX() 系列方法 |
| 复用机制 | 两级缓存 | 四级缓存(更强大) |
七、RecyclerView 四级缓存机制
RecyclerView 的缓存系统是其高性能的核心:
plain
┌─────────────────────────────────────────────────────────┐
│ 1. mChangedScrap / mAttachedScrap │
│ → 布局期间临时缓存,同一帧内复用(如调用 notifyDataSetChanged)│
├─────────────────────────────────────────────────────────┤
│ 2. mCachedViews (默认容量 = 2) │
│ → 刚滑出屏幕的 ViewHolder,按位置缓存,可直接复用 │
├─────────────────────────────────────────────────────────┤
│ 3. mViewCacheExtension (可选,需自定义) │
│ → 开发者自定义缓存策略,如 ViewPager 内嵌 RecyclerView │
├─────────────────────────────────────────────────────────┤
│ 4. mRecycledViewPool (按 viewType 缓存,默认每种 5 个) │
│ → 最终缓存池,ViewHolder 与位置解耦,需重新绑定数据 │
└─────────────────────────────────────────────────────────┘
八、总结
RecyclerView 是 Android 列表开发的事实标准,核心要点:
-
四大组件各司其职:Adapter 管数据、LayoutManager 管布局、ViewHolder 管视图缓存、ItemDecoration 管装饰
-
优先使用
ListAdapter+DiffUtil:自动差异计算,避免手动刷新 -
注意性能细节:
setHasFixedSize(true)、避免onBindViewHolder中创建对象、正确使用点击监听 -
善用官方扩展库:Paging 3 分页、ConcatAdapter 多 Adapter 组合、Selection 库多选支持
更多推荐


所有评论(0)