首页 > 解决方案 > 如何从 RecyclerView 适配器调用 ViewModel.delete?

问题描述

我想从我的 Recyclerview 适配器调用我的 ViewModel.delete(房间数据库)方法,但它不起作用。有任何想法吗?

我想在 OnBindViewHolder 中调用 ViewModel,例如: holder.binding.ivItemWalletDelete.setOnClickListener { WalletViewModel... }

但我得到了错误:在一个空对象上

RecyclerView 适配器 (WalletListAdapter.kt)

class WalletListAdapter:
        ListAdapter<Wallet, WalletListAdapter.ViewHolder>(WalletDiffCallback()){

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder {
        return ViewHolder.from(parent)
    }


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

    class ViewHolder private constructor(val binding: ItemWalletsBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(item: Wallet) {
            binding.wallet = item
            binding.executePendingBindings()
        }

        companion object {
            fun from(parent: ViewGroup): ViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
                val binding = ItemWalletsBinding.inflate(layoutInflater, parent, false)
                return ViewHolder(binding)
            }
        }
    }
}

class WalletDiffCallback : DiffUtil.ItemCallback<Wallet>() {
    override fun areItemsTheSame(oldItem: Wallet, newItem: Wallet): Boolean {
        return oldItem.walletId == newItem.walletId
    }

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

视图模型 (WalletViewModel.kt)

class WalletViewModel(application: Application): AndroidViewModel(application) {
    private val repository = WalletRepository(application)
    private val liveWalletList = repository.getLiveDataWallets()

    fun insert(wallet: Wallet){
        viewModelScope.launch {
            repository.insert(wallet)
        }
    }

    fun update(wallet: Wallet){
        viewModelScope.launch {
            repository.update(wallet)
        }
    }

    fun delete(wallet: Wallet){
        viewModelScope.launch {
            repository.delete(wallet)
        }
    }

    fun getWalletById(walletId: Long): Wallet? {
        var wallet: Wallet? = null
        viewModelScope.launch {
            wallet = repository.getWalletById(walletId)
        }
        return wallet
    }

    fun getAllWallets(): List<Wallet>? {
        var wallets: List<Wallet>? = null
        viewModelScope.launch {
            wallets = repository.getAllWallets()
        }
        return wallets
    }

    fun getLiveWalletList(): LiveData<List<Wallet>> = liveWalletList
} 

标签: androidkotlinmvvmandroid-recyclerviewviewmodel

解决方案


解决此类问题的一种常见方法是创建一个回调,该回调将传递给适配器。

在你的WalletListAdapter类中传入一个接受Wallet对象的回调。

class WalletListAdapter(private val onDeleteCallback: (Wallet) -> Unit) {}

ViewHolder可以OnClickListener在每个回收站视图项上设置一个并将Wallet对象传递给回调函数。看起来像这样:

binding.root.setOnClickListener { onDeleteCallback(item) }

最后,初始化 的视图(活动、片段等)WalletListAdapter将传入一个接受Wallet对象的函数。然后在这里调用WalletViewModel's delete 函数。

class WalletListActivity: Activity() {

  @Inject
  lateinit var viewModel: WalletViewModel

  override fun onCreate(bundle: Bundle?) {
    super.onCreate(savedInstanceState)
    
    // initialize the WalletListAdapter and pass in the callback
    val adapter = WalletListAdapter(::deleteWallet)

  }

  private fun deleteWallet(wallet: Wallet) {
    viewModel.delete(wallet)
  }

}

注意:你可以先WalletListAdapter用一个空的构造函数初始化类,然后创建一个方法,将视图的回调函数传递给WalletListAdapter类。关键是将点击事件从适配器“传播”回视图,因此视图可以调用视图模型的方法。


推荐阅读