从 RecyclerView 适配器中访问 ViewModel 函数

Accessing ViewModel functions from within a RecyclerView adapter

我是 Android 开发的新手,正在研究一些基本的 Android 应用程序以了解更多信息。我想尽早学习 MVMM 架构最佳实践,并且很好奇如何最好地解决以下任务:在一个简单的列表应用程序中,我的 ViewModel 包含列表数据以及用于添加和删除数据的函数(我从 Android 开发者教程)。

RecyclerView 在Fragment 中显示列表数据。我将 RecyclerView 适配器用作用户与之交互的 UI 列表项和适当的 ViewModel 函数调用之间的 'bridge'。最初,我使用接口实现了它,但这不允许我将对 ViewModel 的引用作为构造函数参数传递,所以现在我使用内部 class ,如许多​​关于在 RecyclerView 适配器中设置 ClickListeners 的 SO 帖子中所述:

class MainAdapter(
    val viewModel: ListViewModel, // reference to entire ViewModel just to access functions therein
    private var list: LiveData<MutableList<String>>, // stored in ViewModel
    private val listener: OnItemClickListener // defined in inner class below
) :
    RecyclerView.Adapter<MainAdapter.ViewHolder>() {

    inner class OnItemClickListener(viewModel: ListViewModel) { 
        fun onClick(mainItem: String) {
            // (TODO) navigate to DetailListFragment and display appropriate list
        }

        fun onLongClick(mainItem: String) {
            // contact viewModel to delete this item
            viewModel.deleteItemMainList(mainItem)
        }
    }

    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view)

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

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.itemView.list_item_text.text = list.value?.elementAt(position)
        holder.itemView.setOnClickListener(View.OnClickListener {
            listener.onClick(list.value?.elementAt(position)!!)
        })
        holder.itemView.setOnClickListener(View.OnClickListener {
            listener.onLongClick(list.value?.elementAt(position)!!)
        })
    }

    override fun getItemCount(): Int {
        return list.value?.size ?: 0
    }

}

有没有比只传递对我的整个 ViewModel 的引用以访问其中的函数更好的解决方案?

如果这是最合适的解决方案,我在片段 class 中初始化适配器时遇到错误:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        ...

        // Error: 
        // Constructor of inner class OnItemClickListener can be called only with receiver of containing class: 
        adapter = MainAdapter(viewModel ,viewModel.mainList, MainAdapter.OnItemClickListener(viewModel) )
        
        main_list_view.adapter = adapter
        main_list_view.layoutManager = LinearLayoutManager(requireContext())
        recyclerView = binding.mainListView
    }

我的 ViewModel 包含数据和函数:

class ListViewModel : ViewModel() {
    private val _mainList = MutableLiveData<MutableList<String>>()
    val mainList: LiveData<MutableList<String>> = _mainList

    init {
        _mainList.value = arrayListOf()
        _detailList.value = arrayListOf(arrayListOf())
    }

    fun addItemMainList(item: String) {
        if (_mainList.value?.contains(item) == false) {
            _mainList.value?.add(item)
            _mainList.value = _mainList.value
            }
    }

    fun deleteItemMainList(item: String) {
        _mainList.value?.remove(item)
        _mainList.value = _mainList.value
    }
}

最后,我意识到以这种方式存储列表数据不是持久化的,Room 是持久化数据的合适方式,但首先我想了解如何使用 MVMM 最佳实践正确连接 UI 事件和我的 ViewModel .

到目前为止探索的参考样本:

https://discuss.kotlinlang.org/t/kotlin-constructor-of-inner-class-nested-can-be-called-only-with-receiver-of-containing-class/7700

。来自您共享的资源之一的评论回答了您的问题。只需传递必要的内容(例如列表),然后在您的 recyclerView 中创建接口以在调用 activity 或 Fragment 中调用。然后从那里访问您的 Viewmodel。

可以将 ViewModel 传递给 recyclerView 吗?..我的意思是回收器视图将绑定到片段的生命周期或者 activity 你从回收器视图调用它所以没关系但不是一个好的做法