RecyclerView 不更新屏幕
RecyclerView does not update the screen
我正在尝试通过按钮添加项目。
我用了ListAdapter
和DiffUtil
。
然而,当按下按钮时,第一个项目被更新,但之后屏幕没有更新。
我用 Adapter
和 DiffUtil
试过 debugging
。
我通过适配器中的currentList
检查了List
是否submitted
,但是断点只对第一个项目有效,不会为项目停止之后添加。
在DiffUtil
中,我们确认break point
根本不起作用。
我写错了什么代码?
片段
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentWriteRoutine2Binding.inflate(inflater, container, false)
adapter = DetailAdapter()
binding.apply {
rv.adapter = adapter
rv.itemAnimator = null
header.add.setOnClickListener {
vm.addDetail()
}
header.delete.setOnClickListener {
vm.deleteDetail()
}
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
vm.items.observe(viewLifecycleOwner) { newList ->
adapter.submitList(newList)
}
}
RoutineItem
sealed class RoutineItem(
val id: String,
) {
class Header(
id: String = UUID.randomUUID().toString(),
val workout: String,
val unit: String,
) : RoutineItem(id)
class Detail(
id: String = UUID.randomUUID().toString(),
val set: Int,
var weight: String = "",
var reps: String = "",
) : RoutineItem(id)
}
适配器
class DetailAdapter
: ListAdapter<RoutineItem, DetailAdapter.ViewHolder>(RoutineDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
ItemRoutineDetailBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val cur = currentList
}
inner class ViewHolder(val binding: ItemRoutineDetailBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: RoutineItem.Detail) {
}
}
}
DiffUtilCallback
class DetailDiffCallback : DiffUtil.ItemCallback<RoutineItem>() {
override fun areItemsTheSame(
oldItem: RoutineItem,
newItem: RoutineItem
): Boolean = (oldItem.id == newItem.id)
override fun areContentsTheSame(
oldItem: RoutineItem,
newItem: RoutineItem
): Boolean = (oldItem == newItem)
}
因为您没有使用 data
classes 作为您的 Header 和 Detail classes,它们的 equals()
函数不适合在 ==
中使用你的DiffUtil.ItemCallback
。 data
class 会自动比较其在 equals
中的所有构造函数属性,但常规 class 不会。您可以手动为它们编写适当的 equals
和 hashcode
实现(IntelliJ IDEA 可以为您生成),或者您可以将它们更改为数据 classes.
此外,在大多数情况下,密封接口比密封 classes 使用起来更干净一些。 Kotlin 中有这么多密封 classes 示例的原因可能是直到最近(Kotlin 1.5)才支持密封接口。
这里是定义项目的方法 classes:
sealed interface RoutineItem {
val id: String
data class Header(
override val id: String = UUID.randomUUID().toString(),
val workout: String,
val unit: String,
) : RoutineItem
data class Detail(
override val id: String = UUID.randomUUID().toString(),
val set: Int,
var weight: String = "",
var reps: String = "",
) : RoutineItem
}
除此之外,您分享的 DetailAdapter 代码看起来很不完整。它没有实际尝试将任何数据绑定到视图。
另一个小提示:由于 DiffUtil.ItemCallbacks 通常不携带任何状态,您可以将它们定义为 object
而不是 class
,这样您就不必调用它们构造函数或有它们的多个实例。
我正在尝试通过按钮添加项目。
我用了ListAdapter
和DiffUtil
。
然而,当按下按钮时,第一个项目被更新,但之后屏幕没有更新。
我用 Adapter
和 DiffUtil
试过 debugging
。
我通过适配器中的currentList
检查了List
是否submitted
,但是断点只对第一个项目有效,不会为项目停止之后添加。
在DiffUtil
中,我们确认break point
根本不起作用。
我写错了什么代码?
片段
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentWriteRoutine2Binding.inflate(inflater, container, false)
adapter = DetailAdapter()
binding.apply {
rv.adapter = adapter
rv.itemAnimator = null
header.add.setOnClickListener {
vm.addDetail()
}
header.delete.setOnClickListener {
vm.deleteDetail()
}
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
vm.items.observe(viewLifecycleOwner) { newList ->
adapter.submitList(newList)
}
}
RoutineItem
sealed class RoutineItem(
val id: String,
) {
class Header(
id: String = UUID.randomUUID().toString(),
val workout: String,
val unit: String,
) : RoutineItem(id)
class Detail(
id: String = UUID.randomUUID().toString(),
val set: Int,
var weight: String = "",
var reps: String = "",
) : RoutineItem(id)
}
适配器
class DetailAdapter
: ListAdapter<RoutineItem, DetailAdapter.ViewHolder>(RoutineDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
ItemRoutineDetailBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val cur = currentList
}
inner class ViewHolder(val binding: ItemRoutineDetailBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: RoutineItem.Detail) {
}
}
}
DiffUtilCallback
class DetailDiffCallback : DiffUtil.ItemCallback<RoutineItem>() {
override fun areItemsTheSame(
oldItem: RoutineItem,
newItem: RoutineItem
): Boolean = (oldItem.id == newItem.id)
override fun areContentsTheSame(
oldItem: RoutineItem,
newItem: RoutineItem
): Boolean = (oldItem == newItem)
}
因为您没有使用 data
classes 作为您的 Header 和 Detail classes,它们的 equals()
函数不适合在 ==
中使用你的DiffUtil.ItemCallback
。 data
class 会自动比较其在 equals
中的所有构造函数属性,但常规 class 不会。您可以手动为它们编写适当的 equals
和 hashcode
实现(IntelliJ IDEA 可以为您生成),或者您可以将它们更改为数据 classes.
此外,在大多数情况下,密封接口比密封 classes 使用起来更干净一些。 Kotlin 中有这么多密封 classes 示例的原因可能是直到最近(Kotlin 1.5)才支持密封接口。
这里是定义项目的方法 classes:
sealed interface RoutineItem {
val id: String
data class Header(
override val id: String = UUID.randomUUID().toString(),
val workout: String,
val unit: String,
) : RoutineItem
data class Detail(
override val id: String = UUID.randomUUID().toString(),
val set: Int,
var weight: String = "",
var reps: String = "",
) : RoutineItem
}
除此之外,您分享的 DetailAdapter 代码看起来很不完整。它没有实际尝试将任何数据绑定到视图。
另一个小提示:由于 DiffUtil.ItemCallbacks 通常不携带任何状态,您可以将它们定义为 object
而不是 class
,这样您就不必调用它们构造函数或有它们的多个实例。