RecyclerView 的 ViewHolders 变得不可点击

RecyclerView's ViewHolders becoming unclickable

史前

我有一份来自 RoomDB 的股票(一些对象)列表。他们每个人都有“符号”,“名称”, “价格”和最重要的 “isFavourite” 字段。 我制作了一个 ViewPager2,其中包含两个包含 RecyclerView 的片段(实际上只有一个 class StocksFragment 的两个实例 - 一个用于所有股票,一个仅用于最喜欢的股票)。 RecyclerView 中的每个股票都通过 Obsrver 连接到存储库(数据变化 => 股票的 ViewHolder 变化)。此外,每个 ViewHolder 都有自己的复选框,它通过调用 StockRepository 的 StockListViewModel 更改“isFavourite”Stock 字段,它直接与 roomDB 一起工作(与 kotlin 协程 - 类似 fun getStocks(): LiveData<List<Stock>> = runBlocking{ stockDao.getStocks() })

问题

当我在相对较短的时间内多次单击同一个复选框时,所有 RecyclerView 的 ViewHolder 都变得不可单击(删除按钮和复选框都不起作用)。 但我仍然可以滚动 RecyclerView 我该如何解决这个问题? 我想我正在做一些非常低效的事情,但我不知道是什么。

这是我的 StocksFragment 代码:

package com.nikitakrapo.android.happystocks

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class StocksFragment(var stockListType: StockListType) : Fragment() {
    private val stockListViewModel: StockListViewModel by lazy{
        ViewModelProvider(this).get(StockListViewModel::class.java)
    }

    private lateinit var stocksRecyclerView: RecyclerView
    private var adapter: StocksAdapter? = StocksAdapter()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_stocks, container, false)

        stocksRecyclerView = view.findViewById(R.id.recycler_view)
        stocksRecyclerView.layoutManager = LinearLayoutManager(context)
        stocksRecyclerView.setHasFixedSize(true)
        stocksRecyclerView.adapter = adapter

        return view
    }

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

        var stocks = if (stockListType == StockListType.favouriteStocksList)
                        stockListViewModel.favStockListLiveData
                        else stockListViewModel.stockListLiveData
        stocks.observe(
            viewLifecycleOwner,
                { stocks ->
                    stocks?.let {
                        adapter?.setStocks(stocks)
                    }
                }
        )
    }

    private inner class StockHolder(view: View) : RecyclerView.ViewHolder(view){

        private lateinit var stock: Stock

        val symbolTextView: TextView = itemView.findViewById(R.id.stock_symbol)
        private val nameTextView: TextView = itemView.findViewById(R.id.stock_name)
        private val priceTextView: TextView = itemView.findViewById(R.id.stock_price)
        private val stockImageView: ImageView = itemView.findViewById(R.id.stock_image)
        val stockDeleteButton: Button = itemView.findViewById(R.id.stock_delete)
        val favouriteCheckBox: CheckBox = itemView.findViewById(R.id.is_favourite)

        fun bind(stock: Stock, holder: StockHolder) {
            this.stock = stock
            symbolTextView.text = this.stock.symbol
            nameTextView.text = this.stock.name
            priceTextView.text = "$" + this.stock.priceUSD.toString()
            favouriteCheckBox.isChecked = this.stock.isFavourite
            holder.stockDeleteButton.setOnClickListener {
                stockListViewModel.deleteStock(stock)
            }
            holder.favouriteCheckBox.setOnCheckedChangeListener { buttonView, isChecked ->
                stockListViewModel.updateFavourite(holder.symbolTextView.text.toString(), isChecked)
            }
        }
    }

    private inner class StocksAdapter
        : RecyclerView.Adapter<StockHolder>() {
        private var stockList: List<Stock> = emptyList()

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int)
                : StockHolder {
            val view = layoutInflater.inflate(R.layout.list_item_stock, parent, false)
            return StockHolder(view)
        }

        override fun onBindViewHolder(holder: StockHolder, position: Int) {
            val stock = stockList[position]
            holder.bind(stock, holder)
        }

        public fun setStocks(stockList: List<Stock>){
            this.stockList = stockList
            notifyDataSetChanged()
        }

        override fun getItemCount() = stockList.size
    }
}

改用 OnClickListener

holder.favouriteCheckBox.setOnClickListener {
    if ((it as CompoundButton).isChecked) {
        stockListViewModel.updateFavourite(holder.symbolTextView.text.toString(), (it as CompoundButton).isChecked)
    }
}

并提供stockListViewModel.updateFavourite代码块。注释掉此行后问题是否重现?

在后台线程中调用 stockListViewModel.deleteStock(stock) stockListViewModel.updateFavourite(holder.symbolTextView.text.toString(), isChecked) withContext(Dispatchers.IO){stockListViewModel.deleteStock(stock)} 可能会解决问题。