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)}
可能会解决问题。
史前
我有一份来自 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)}
可能会解决问题。