Erdem
Erdem

Reputation: 81

How to call ViewModel.delete from RecyclerView Adapter?

I want to call my ViewModel.delete (Room Database) method from my Recyclerview Adapter but it's not working. Any ideas?

I want to call the ViewModel in OnBindViewHolder like: holder.binding.ivItemWalletDelete.setOnClickListener { WalletViewModel... }

but I get the error: on a null object

RecyclerView Adapter (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
    }
}

ViewModel (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
} 

Upvotes: 2

Views: 2038

Answers (1)

Tobi Daada
Tobi Daada

Reputation: 533

A common way of tackling this kind of problem would be to create a callback that would be passed into the adapter.

In your WalletListAdapter class pass in a callback that takes a Wallet object.

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

In your ViewHolder you can set an OnClickListener on each recycler view item and pass in the Wallet object to the callback function. That would look something like this:

binding.root.setOnClickListener { onDeleteCallback(item) }

Finally, the view (activity, fragment, etc) that initialized the WalletListAdapter would pass in a function that accepts a Wallet object. This is where you then call the WalletViewModel's delete function.

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)
  }

}

Note: You can first initialize the WalletListAdapter class with an empty constructor, then create a method to pass in the callback function from the view to the WalletListAdapter class. The point is to "propagate" the click event from the adapter back to the view, so the view can call the viewmodel's method.

Upvotes: 2

Related Questions