android-recyclerview - 双向数据绑定、RecyclerView、ViewModel、Room、LiveData、Oh My
问题描述
刚接触 Android 开发,我正在尝试结合 RecyclerView、ViewModel、Room 和 LiveData 进行双向数据绑定。我摸索单向绑定,但无法弄清楚双向。
简单地说,我希望能够点击 id/switch_enabled 开关并更新 Db 以反映这一点(然后我计划利用它来更新类/Db 中的其他成员)。我想我需要一些帮助来处理我的 ViewModel 上的 set(value) 并在 Db 中更新正确的 RecyclerView 项目,但我不确定如何执行此操作,或者这是否是正确或最佳的方法。
谢谢你。
班级:
data class Person (@ColumnInfo(name = "first_name") val firstName: String,
@ColumnInfo(name = "last_name") val lastName: String,
//...
val enabled: Boolean = true
){
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}
RecyclerView 的布局细节:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="p" type="com.example.data.Person" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/first_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{p.firstName}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="John" />
<TextView
android:id="@+id/last_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:text="@{' ' + p.lastName}"
app:layout_constraintStart_toEndOf="@id/first_name"
app:layout_constraintTop_toTopOf="parent"
tools:text=" Doubtfire" />
<Switch
android:id="@+id/switch_enabled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@={p.enabled}"
app:layout_constraintBaseline_toBaselineOf="@id/last_name"
app:layout_constraintEnd_toEndOf="parent" />
<!--...-->
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
视图模型:
class MainViewModel(private val repository: DataRepository) : ViewModel() {
private val _people: LiveData<List<Person>>
// @Bindable?
// @get:Bindable?
var people: LiveData<List<Person>>
@Bindable
get() = _people
set(value) {
//Find out which member of the class is being changed and update the Db?
Log.d(TAG, "Value for set is $value!")
}
init {
_people = repository.livePeople()
}
}
分段:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val binding = FragmentPeopleBinding.inflate(inflater, container, false)
val context = context ?: return binding.root
val factory = Utilities.provideMainViewModelFactory(context)
viewModel = ViewModelProviders.of(requireActivity(), factory).get(MainViewModel::class.java)
val adapter = PeopleViewAdapter()
viewModel.people.observe(this, Observer<List<Person>> {
adapter.submitList(it)
})
binding.apply {
vm = viewModel
setLifecycleOwner(this@PeopleFragment)
executePendingBindings()
rvPeopleDetails.adapter = adapter
}
return binding.root
}
列表适配器:
class PeopleViewAdapter: ListAdapter<Person, PeopleViewAdapter.ViewHolder>(PeopleDiffCallback()) {
class PeopleDiffCallback : DiffUtil.ItemCallback<Person>() {
override fun areItemsTheSame(oldItem: Person, newItem: Person): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Person, newItem: Person): Boolean {
return oldItem.number == newItem.number
}
}
class ViewHolder(val binding: FragmentPeopleDetailBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(person: Person) {
binding.p = person
}
}
@NonNull
override fun onCreateViewHolder(@NonNull parent: ViewGroup, viewType: Int): ViewHolder =
ViewHolder(FragmentPeopleDetailBinding.inflate(LayoutInflater.from(parent.context), parent, false))
@NonNull
override fun onBindViewHolder(@NonNull holder: ViewHolder, position: Int) {
holder.apply {
bind(getItem(position))
}
}
}
解决方案
我刚刚遇到了在具有 ViewModel 和 RecyclerView 列表的 MVVM 架构中设置两种方式数据绑定的相同问题。我确定在这种情况下实现双向绑定是不可能或不值得努力的,因为您没有直接在 recyclerview 项目布局中使用视图模型(您使用的布局变量是 Person 类型,而不是你的视图模型)。
我建议实际上将您的视图模型添加为布局变量,然后android:onClick="@{() -> viewmodel.onSwitchClicked()}"
在您的视图模型中使用和实现该方法。
在此处查看我的项目中的详细信息:https ://github.com/linucksrox/ReminderList
推荐阅读
- c++ - 用于颜色的 C++ constexpr 构造函数
- azure - 不支持 Azure Functions CRON 表达式?
- javascript - 监听悬停元素上的 DOM 变化
- javascript - 如何生成一个可以打开 Instagram 应用程序并与用户分享一些文本的网络链接?
- java - Spring Cloud Stream Kafka Binder 配置在运行时更新
- image - s从sharex上传到github repo?
- azure - 如何使用 Azure Management Fluent API 获取 Azure SQL 托管实例中的数据库大小?
- ios - 如何构建和分发 iOS 调试版本?
- python - 使用 py2app 从 python 脚本创建 MAC 应用程序
- javascript - 使用摘要和详细信息标签的手风琴 - 如何慢慢打开