首页 > 解决方案 > 不会 notifyDataSetChanged() 在 Android Studio 的 RecyclerView.ViewHolder 中启动 init{ }?

问题描述

我正在使用 ListAdapter 学习 RecyclerView。

1:我发现setControl()init{ }我运行后没有启动notifyDataSetChanged(),为什么?

2:我应该把它放在什么代码中init{ }?我应该把它放在什么代码中fun bind(aMVoice: MVoice{ }

代码

class VoiceAdapters (private val aHomeViewModel: HomeViewModel):
        ListAdapter<MVoice, VoiceAdapters.VoiceViewHolder>(MVoiceDiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VoiceViewHolder {
        return VoiceViewHolder(
            LayoutVoiceItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        )
    }

    override fun onBindViewHolder(holder: VoiceViewHolder, position: Int) {
        val aMVoice = getItem(position)
        holder.bind(aMVoice)
    }

    inner class VoiceViewHolder (private val binding: LayoutVoiceItemBinding):
          RecyclerView.ViewHolder(binding.root) {

       
        init {
            setControl()
        }

        fun bind(aMVoice: MVoice) {
            binding.amVoice = aMVoice                
            binding.executePendingBindings()
        }

       
        fun setControl(){    
           binding.aHomeViewModel = aHomeViewModel    
           binding.chSelect.setOnCheckedChangeListener{ _, isChecked ->
                binding.amVoice?.let {
                   ...
                }
            }
             
            ...
         }

    }
}

添加内容:

致 ADM:非常感谢!

A:为什么将 ViewModel 传递给 adapter 不是一个好主意?

B: 我怎样才能使用界面呢?你能给我看一些示例代码吗?

BTW,下面 RecyclerView 的 item 布局需要使用 ViewModelaHomeViewModel来控制 CheckBoxchSelect是否显示。我将aHomeViewModel.displayCheckBox在片段中设置 的值。

layout_voice_item.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>
    <import type="android.view.View" />

    <variable name="aMVoice"
        type="info.dodata.voicerecorder.model.MVoice"  />
   
    <variable name="aHomeViewModel"
        type="info.dodata.voicerecorder.viewcontrol.HomeViewModel" />
</data>


<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"   
    android:orientation="horizontal">

    <CheckBox
        android:id="@+id/chSelect"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="@{aHomeViewModel.displayCheckBox? View.VISIBLE: View.GONE}"
        android:text="" />

    <TextView
       android:id="@+id/voiceID"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@{Integer.toString(aMVoice.id)}" />

</LinearLayout>
</layout>

标签: androidandroid-recyclerview

解决方案


RecyclerViewViewHolder多次重复使用相同的东西,这就是构造函数不被调用的原因。所以任何应该为所有项目做的绑定东西都应该写在里面onBindViewHolder

调用notifyDataSetChanged onBindViewHolder时将调用屏幕上可见的位置,并且ViewHolder将重复使用相同的位置(这取决于)。但是这里的事情是ViewHolder每次都不会创建一个新的,所以你不能使用构造函数进行这样的操作。

我应该在 init{ } 中放置什么代码?我应该将什么代码放在 fun bind(aMVoice: MVoice{ } 中?

在里面init你可以找到视图并设置动作监听器。你在里面bind为每个项目做这些事情,即为视图设置数据。

另一方面,您不应该将 a 传递ViewModel给不是一个好主意的适配器,interface而是使用 an 。

为什么你不将 ViewModel 传递给 Adapter Well 最终ViewModel只是一个类,所以你可以传递它并且它不会给出任何错误。我现在能想到的不这样做的原因如下:-

  1. 通过传递ViewModelyo 将适配器紧密耦合到单个ViewModel,即轮流 Activity 或片段。现在你不能在任何其他地方重用这个适配器

  2. 还有一个重点ViewModel是观察通常不会在适配器内部发生的数据流。

记住一件事ViewModel(LiveData)不是回调接口的替代品。所以你应该在这里使用回调接口因为你在这里不需要生命周期组件。

因此,不要ViewModel直接将数据集传递给适配器,如果您需要通知Activity操作Fragment(单击、长按),请使用接口。


推荐阅读