需求
点击 RecyclerView 中的一个 checkbox 子项,更新本地 sqlite 数据库中的一行数据的选中状态字段。
方案对比:
方案一 (不可行):使用 Data Binding 事件处理机制中的 listener binding。
参考
https://developer.android.com/topic/libraries/data-binding/expressions#listener_bindings
采用这个方案,就能把事件响应方法放在 Fragment 中,也就可以使用 Fragment 中的 View Model 了,进而进行 Room Update 操作。
唯一不确定的就是 Fragment 能否作为变量放入 Layout 中,而且每个子项的 layout 都引入一遍 fragment 会不会有内存问题。
愚蠢如我,在 codelabs 中发现了正确的做法
https://developer.android.com/codelabs/android-databinding#5
即,layout 中直接引入 View Model:
<data>
<variable name="viewmodel" type="com.example.android.databinding.basicsample.data.SimpleViewModel"/>
</data>
但是在 adapter 中如何赋值呢?
尝试在 adapter 中获取 view model:
https://stackoverflow.com/questions/44495323/how-to-use-architecture-components-viewmodel-inside-recyclerview-adapter
https://stackoverflow.com/questions/61364874/view-models-for-recyclerview-items
adapter 与 fragment 的数据交互
https://stackoverflow.com/questions/56336566/how-to-send-data-from-adapter-to-viewmodel-to-fragment
很多文章里说给 adapter 传递 view model 并不是推荐的做法。所以放弃。
方案二 (未测试):传递函数给 adapter
参考
https://stackoverflow.com/questions/65504527/update-status-from-viewholder-on-click-android-kotlin
https://www.avinsharma.com/android-basics-recyclerview-II/
方案三 (可行):使用 interface 实现
在 RecyclerView Adapter 的 View Holder 中设置响应事件处理方法。
一个非常详细的说明
https://stackoverflow.com/questions/63266686/how-do-i-remove-a-row-from-recyclerview-using-room
最终实现方案
最终参照第三个方案,采用 interface 的实现。这个方案虽然有点复杂,但是思路清晰,我觉得不错。
实现步骤:
1、adapter 中添加一个 interface,内置一个响应点击的函数
private lateinit var listener: ItemListener
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val todo = getItem(position)
holder.bind(todo)
holder.binding.checkBox.setOnCheckedChangeListener {_, isChecked ->
listener.onItemClicked(todo, isChecked)
}
}
interface ItemListener {
fun onItemClicked(item: Todo, isChecked: Boolean)
}
fun setListener(listener: ItemListener) {
this.listener = listener
}
2、fragment 中实现这个 interface
class TodosFragment : Fragment(), TodoAdapter.ItemListener {
...
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
...
adapter.setListener(this)
...
}
override fun onItemClicked(item: Todo, isChecked: Boolean) {
item.done = if (isChecked) 1 else 0
viewModel.updateTodo(item)
}
}
data binding 中 listener binding 无响应的原因
android:onClick="@{(theView) -> fragment.completeChanged(todo)}"
android:onCheckedChanged="@{(cb, isChecked) -> fragment.completeChanged(todo, isChecked)}"
点击无响应。原因是没有对 layout 中的变量进行赋值 。。。
// checked handler for recycler view item
binding.viewmodel = viewModel
kotlin interface 介绍
https://oozou.com/blog/interface-in-kotlin-and-when-to-use-it-10
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式