在传统 Android UI 开发中,RecyclerView 是构建列表 UI 的标配组件,但是当需要处理多种不同类型的 item 时,它的编写成本和维护成本会突然上升。
这不仅是编码的煮烤,还有一堆策略不符 SRP、OCP 等设计原则的问题。
而 Jetpack Compose 的出现,则从根本上解决了这一系列问题,并提供了更现代、声明式、易维护的规划方式。
为什么 RecyclerView 写起来这么累?
- 需要重写
getItemViewType()
,分类管理 ViewType - 在
onCreateViewHolder()
中进行大量\uwhen
或if
分支 - 在
onBindViewHolder()
中再条件判断绑定数据 - 每增加一种 item 类型,都需要修改多处代码,异味 SRP 和 OCP
- ViewHolder 类内联 UI 和数据的组合,越来越难维护
实际上,一个处理多类型 item 的 Adapter 很容易变成“无限的 if/else” 、“大型 when 场面” 和“一览不清的熟二演示”。
Compose 怎么做到一切都好好的
Jetpack Compose 推行声明式 UI,不再需要 Adapter + XML + ViewHolder 等组合,使用者只需输入“怎么显示”,而不用关心“什么时候显示”。
LazyColumn 直接替代 RecyclerView
Compose 中的 LazyColumn 是用于列表显示的组件,用法极为简洁:
LazyColumn {
items(myList) { item ->
when (item) {
is ListItem.Title -> TitleItem(item)
is ListItem.Content -> ContentItem(item)
is ListItem.Image -> ImageItem(item)
}
}
}
不再需要:
- getItemViewType
- onCreateViewHolder
- onBindViewHolder
- Adapter/ViewHolder
你才是 UI 展示的主管,不再是工厂和导演了。
演示 Demo :Compose 下的多类型列表
1. 数据模型
sealed class ListItem {
data class Title(val text: String) : ListItem()
data class Content(val description: String) : ListItem()
data class Image(val url: String) : ListItem()
}
2. UI 组件
@Composable
fun TitleItem(item: ListItem.Title) {
Text(
text = item.text,
style = MaterialTheme.typography.titleLarge,
modifier = Modifier.padding(16.dp)
)
}
@Composable
fun ContentItem(item: ListItem.Content) {
Text(
text = item.description,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
)
}
@Composable
fun ImageItem(item: ListItem.Image) {
AsyncImage(
model = item.url,
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.height(180.dp)
.padding(8.dp),
contentScale = ContentScale.Crop
)
}
提示:
AsyncImage
来自coil-compose
库,可以用 Glide 或 Accompanist 替代
3. 主组织 UI
@Composable
fun MultiTypeList(items: List<ListItem>) {
LazyColumn {
items(items) { item ->
when (item) {
is ListItem.Title -> TitleItem(item)
is ListItem.Content -> ContentItem(item)
is ListItem.Image -> ImageItem(item)
}
}
}
}
4. ComposeView 引入,实现混合开发
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val sampleData = listOf(
ListItem.Title("标题 1"),
ListItem.Content("这是一段内容"),
ListItem.Image("https://picsum.photos/300/200"),
ListItem.Title("标题 2"),
ListItem.Content("这是第二段内容")
)
MaterialTheme {
MultiTypeList(sampleData)
}
}
}
}
总结
传统 RecyclerView 在处理复杂列表时带来不少编码粗重和维护性较差的问题,Jetpack Compose 使用声明式、减少代码、分类精精的方式解决了这一切。
而逐步迁移,可以从 ComposeView 开始,先试验小段代码,再手揣全面迁移。
实现简单,精神不乱。Compose 就是最好的移动 UI 之道。