主线程和数据库访问出现问题
Trouble with mainUIThread and database acces
我有需要从数据库数据中获取并通过适配器放入 UI 的功能
但是如果我在第二个线程中创建,我会捕获异常
只有创建视图层次结构的原始线程才能触及它的视图。
如果我在 mainThread 中创建,我会捕获异常
无法在主线程上访问数据库,因为它可能会长时间锁定 UI。
(db.dao.drinks() - 从数据库 Room 和 return MutableList< Drink >) 中获取所有饮料
我解决了问题,但我想这样太糟糕了。怎么做才对?
private fun loadDrinks(){
Thread {
historyDrinkList = db.dao().drinks()
this@MainActivity.runOnUiThread(java.lang.Runnable {
if (historyDrinkList.isNotEmpty())
this@MainActivity.runOnUiThread(java.lang.Runnable { empty.text = null })
else
clHistory.visibility = View.INVISIBLE
adapter?.updateData(historyDrinkList) })
}.start()
}
适配器
class MainAdapter (private val onDrinkListener: OnDrinkListener): RecyclerView.Adapter<MainAdapter.MainViewHolder>(){
private var drinks = ArrayList<DBDrink>()
private val TAG = "MainAdapter"
private var idDrink: ArrayList<String> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
val binding: ItemDrinkBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context), R.layout.item_drink, parent, false)
return MainViewHolder(binding, onDrinkListener)
}
override fun getItemCount(): Int {
return drinks.size
}
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
holder.bind(drinks[position])
}
fun updateData(drink: List<DBDrink>) {
this.drinks.clear()
this.drinks.addAll(drink)
notifyDataSetChanged()
}
inner class MainViewHolder(private val binding: ItemDrinkBinding, private val onDrinkListener: OnDrinkListener) :
RecyclerView.ViewHolder(binding.root), View.OnClickListener {
fun bind(drink: DBDrink) {
binding.drinkName.text = drink.strDrink
binding.drinkImage.load(drink.strDrinkThumb){
transformations(RoundedCornersTransformation(25f))
}
idDrink.add(drink.idDrink)
itemView.setOnClickListener(this)
}
override fun onClick(v: View?) {
onDrinkListener.onDrinkClick(adapterPosition, idDrink)
}
}
interface OnDrinkListener{
fun onDrinkClick(position: Int, idDrink: ArrayList<String>)
}
}
我建议您首先对 MutableList 使用 ViewModel。
因此您可以在代码中使用 ViewModel 而不必使用线程来处理它:
viewModel.getAllDrinks.observe(this, Observer { drinks -> adapter.updateData(drinks)}
在这里您也可以更新您的视图。
你的代码基本上是正确的方法。您在后台线程中从数据库中获取数据,并在主 (UI) 线程中更新 View
s。但是,您可以简化代码,因为您不需要第二个 runOnUiThread()
:
Thread {
historyDrinkList = db.dao().drinks()
this@MainActivity.runOnUiThread(java.lang.Runnable {
if (historyDrinkList.isNotEmpty())
empty.text = null
else
clHistory.visibility = View.INVISIBLE
adapter?.updateData(historyDrinkList) })
}.start()
我有需要从数据库数据中获取并通过适配器放入 UI 的功能 但是如果我在第二个线程中创建,我会捕获异常
只有创建视图层次结构的原始线程才能触及它的视图。
如果我在 mainThread 中创建,我会捕获异常
无法在主线程上访问数据库,因为它可能会长时间锁定 UI。
(db.dao.drinks() - 从数据库 Room 和 return MutableList< Drink >) 中获取所有饮料
我解决了问题,但我想这样太糟糕了。怎么做才对?
private fun loadDrinks(){
Thread {
historyDrinkList = db.dao().drinks()
this@MainActivity.runOnUiThread(java.lang.Runnable {
if (historyDrinkList.isNotEmpty())
this@MainActivity.runOnUiThread(java.lang.Runnable { empty.text = null })
else
clHistory.visibility = View.INVISIBLE
adapter?.updateData(historyDrinkList) })
}.start()
}
适配器
class MainAdapter (private val onDrinkListener: OnDrinkListener): RecyclerView.Adapter<MainAdapter.MainViewHolder>(){
private var drinks = ArrayList<DBDrink>()
private val TAG = "MainAdapter"
private var idDrink: ArrayList<String> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
val binding: ItemDrinkBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context), R.layout.item_drink, parent, false)
return MainViewHolder(binding, onDrinkListener)
}
override fun getItemCount(): Int {
return drinks.size
}
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
holder.bind(drinks[position])
}
fun updateData(drink: List<DBDrink>) {
this.drinks.clear()
this.drinks.addAll(drink)
notifyDataSetChanged()
}
inner class MainViewHolder(private val binding: ItemDrinkBinding, private val onDrinkListener: OnDrinkListener) :
RecyclerView.ViewHolder(binding.root), View.OnClickListener {
fun bind(drink: DBDrink) {
binding.drinkName.text = drink.strDrink
binding.drinkImage.load(drink.strDrinkThumb){
transformations(RoundedCornersTransformation(25f))
}
idDrink.add(drink.idDrink)
itemView.setOnClickListener(this)
}
override fun onClick(v: View?) {
onDrinkListener.onDrinkClick(adapterPosition, idDrink)
}
}
interface OnDrinkListener{
fun onDrinkClick(position: Int, idDrink: ArrayList<String>)
}
}
我建议您首先对 MutableList 使用 ViewModel。
因此您可以在代码中使用 ViewModel 而不必使用线程来处理它:
viewModel.getAllDrinks.observe(this, Observer { drinks -> adapter.updateData(drinks)}
在这里您也可以更新您的视图。
你的代码基本上是正确的方法。您在后台线程中从数据库中获取数据,并在主 (UI) 线程中更新 View
s。但是,您可以简化代码,因为您不需要第二个 runOnUiThread()
:
Thread {
historyDrinkList = db.dao().drinks()
this@MainActivity.runOnUiThread(java.lang.Runnable {
if (historyDrinkList.isNotEmpty())
empty.text = null
else
clHistory.visibility = View.INVISIBLE
adapter?.updateData(historyDrinkList) })
}.start()