使用DataBinding绑定ObservableArrayList到RecyclerView时遇setter缺失报错
这个错误很常见——RecyclerView本身并没有内置支持直接绑定ObservableArrayList的属性,所以我们需要自定义一个BindingAdapter来实现这个功能,同时利用ObservableArrayList的自动通知特性来更新列表。
步骤1:创建自定义BindingAdapter
我们需要写一个静态方法,用@BindingAdapter注解标记,让DataBinding知道如何处理bind:categories_list这个属性:
// 如果你用Java,换成Java静态方法即可 import android.databinding.BindingAdapter import android.support.v7.widget.RecyclerView import android.databinding.ObservableArrayList import android.databinding.ObservableList object RecyclerViewBindingAdapters { @BindingAdapter("categories_list") @JvmStatic fun setCategoriesList(recyclerView: RecyclerView, items: ObservableArrayList<YourDataType>?) { // 获取RecyclerView的自定义Adapter val adapter = recyclerView.adapter as? YourCustomAdapter items?.let { // 给Adapter设置初始数据 adapter?.updateData(it) // 监听ObservableArrayList的变化,自动触发RecyclerView更新 items.addOnListChangedCallback(object : ObservableList.OnListChangedCallback<ObservableArrayList<YourDataType>>() { override fun onChanged(sender: ObservableArrayList<YourDataType>?) { adapter?.notifyDataSetChanged() } override fun onItemRangeChanged(sender: ObservableArrayList<YourDataType>?, positionStart: Int, itemCount: Int) { adapter?.notifyItemRangeChanged(positionStart, itemCount) } override fun onItemRangeInserted(sender: ObservableArrayList<YourDataType>?, positionStart: Int, itemCount: Int) { adapter?.notifyItemRangeInserted(positionStart, itemCount) } override fun onItemRangeMoved(sender: ObservableArrayList<YourDataType>?, fromPosition: Int, toPosition: Int, itemCount: Int) { adapter?.notifyItemMoved(fromPosition, toPosition) } override fun onItemRangeRemoved(sender: ObservableArrayList<YourDataType>?, positionStart: Int, itemCount: Int) { adapter?.notifyItemRangeRemoved(positionStart, itemCount) } }) } } }
记得替换YourDataType为你实际的数据类,YourCustomAdapter为你的RecyclerView Adapter类。同时你的Adapter需要添加一个更新数据的方法:
class YourCustomAdapter : RecyclerView.Adapter<YourViewHolder>() { private var dataList: List<YourDataType> = emptyList() fun updateData(newData: List<YourDataType>) { dataList = newData // 这里不用手动notify,因为BindingAdapter已经监听了Observable的变化 } // 实现Adapter的其他必备方法... }
步骤2:修改XML布局
确保RecyclerView的bind:categories_list指向ViewModel中的ObservableArrayList,同时提前设置好Adapter(可以在XML或代码中初始化):
<?xml version="1.0" encoding="utf-8"?> <layout> <data> <variable name="viewModel" type="com.yourpackage.YourViewModel" /> </data> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" bind:adapter="@{viewModel.categoryAdapter}" bind:categories_list="@{viewModel.categoriesList}" /> </layout>
步骤3:在ViewModel中处理数据
ViewModel里持有ObservableArrayList对象,API调用完成后直接更新列表即可,不需要手动调用notifyChange()——ObservableArrayList会自动通知变化:
class YourViewModel : ViewModel() { val categoriesList = ObservableArrayList<YourDataType>() val categoryAdapter = YourCustomAdapter() fun fetchCategories() { // 模拟API请求 apiService.getCategories().enqueue(object : Callback<List<YourDataType>> { override fun onResponse(call: Call<List<YourDataType>>, response: Response<List<YourDataType>>) { response.body()?.let { categoriesList.clear() categoriesList.addAll(it) // 无需手动通知,Observable会自动触发更新 } } override fun onFailure(call: Call<List<YourDataType>>, t: Throwable) { // 处理请求失败逻辑 } }) } }
为什么之前的方法不行?
RecyclerView的DataBinding属性默认只支持adapter、layoutManager这类基础设置,并没有内置处理ObservableArrayList的setter。我们必须通过自定义BindingAdapter扩展功能,把Observable的变化监听和RecyclerView的更新逻辑绑定起来。
内容的提问来源于stack exchange,提问作者Insane Developer

