首页 > 解决方案 > 与 RecyclerView 的数据绑定未正确呈现

问题描述

我正在尝试将数据绑定与 RecyclerView 一起使用。我设置了一个简单的应用程序,它在 RecyclerView 中显示数字 1 到 50,每行一个。我想对每一行使用数据绑定。

这是我的适配器的代码(请注意,我调用了dataBinding.executePendingBindings()):

class SimpleAdapter
    : ListAdapter<Int, SimpleAdapter.SimpleAdapterViewHolder>(SimpleAdapterDiffUtil()) {

    inner class SimpleAdapterViewHolder(
        private val dataBinding: SimpleAdapterViewHolderBinding
    ) : RecyclerView.ViewHolder(dataBinding.root) {
        fun bind(str: String) {
            Log.e("MYTAG", "setting TextView: $str")
            dataBinding.txtView.text = str
            dataBinding.executePendingBindings()
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleAdapterViewHolder {
        val binding = SimpleAdapterViewHolderBinding.inflate(
            LayoutInflater.from(parent.context), parent, false)
        return SimpleAdapterViewHolder(binding)
    }

    override fun onBindViewHolder(holder: SimpleAdapterViewHolder, position: Int) {
        val stringValue = getItem(position)
        holder.bind(stringValue.toString())
    }
}

private class SimpleAdapterDiffUtil: DiffUtil.ItemCallback<Int>() {

    override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
        return oldItem == newItem
    }

    override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
        return oldItem == newItem
    }
}

这是视图 XML

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="text"
            type="String" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/txt_view"
            android:text="@{text}"
            android:layout_width="match_parent"
            android:layout_height="36dp" />
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="@color/black"
            app:layout_constraintTop_toBottomOf="@id/txt_view"
            />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

这就是它的作用:

在此处输入图像描述

如您所见,在初始屏幕中,没有任何行未正确呈现。当我向下滚动时,我发现它从第 23 行开始渲染。然后,如果我向上滚动,我终于可以看到前面的行被填充了。

如果我将代码更改为使用普通的旧视图,而不是数据绑定,它会按预期工作。代码在这里:

// This works fine!

class SimpleAdapter
    : ListAdapter<Int, SimpleAdapter.SimpleAdapterViewHolder>(SimpleAdapterDiffUtil()) {

    inner class SimpleAdapterViewHolder(
        private val rootView: View
    ) : RecyclerView.ViewHolder(rootView) {
        fun bind(str: String) {
            Log.e("MYTAG", "setting TextView: $str")
            rootView.findViewById<TextView>(R.id.txt_view).text = str
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleAdapterViewHolder {
        val rootView = LayoutInflater.from(parent.context)
            .inflate(R.layout.simple_adapter_view_holder, parent, false)
        return SimpleAdapterViewHolder(rootView)
    }

    override fun onBindViewHolder(holder: SimpleAdapterViewHolder, position: Int) {
        val stringValue = getItem(position)
        holder.bind(stringValue.toString())
    }
}

private class SimpleAdapterDiffUtil: DiffUtil.ItemCallback<Int>() {

    override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
        return oldItem == newItem
    }

    override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
        return oldItem == newItem
    }
}

标签: androidandroid-recyclerviewandroid-databindingandroid-jetpack

解决方案


正如我在您的 xml 中看到的,您正在设置android: text="@{text}" 换句话说,textView 值是从binding.text 您设置dataBinding.txtView.text = str的,它将更新文本。之后使用executePendingDataBinding它的值将被重置为 null 或空的dataBinding.text(aka )。android: text="@{text}"所以你应该设置

dataBinding.text = str

代替

dataBinding.txtView.text = str

推荐阅读