【问题标题】:Trouble with mainUIThread and database acces主线程和数据库访问问题
【发布时间】:2020-07-30 12:06:36
【问题描述】:

我有需要从数据库数据中获取并通过适配器放入 UI 的功能 但是如果我在第二个线程中创建我会捕获异常

只有创建视图层次结构的原始线程才能接触其视图。

如果我在 mainThread 中创建,我会捕获异常

无法访问主线程上的数据库,因为它可能会长时间锁定 UI。

(db.dao.drinks() - 从数据库 Room 中获取所有饮料并返回 MutableList)

我解决了这个问题,但我猜这种方式太糟糕了。怎么做才对?

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


}

【问题讨论】:

    标签: android multithreading kotlin android-room dao


    【解决方案1】:

    您拥有的代码基本上是正确的方法。您在后台线程中从数据库中获取数据,并在主 (UI) 线程上更新 Views。但是,您可以简化代码,因为您不需要第二个 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()
    

    【讨论】:

      【解决方案2】:

      我建议您首先在 MutableList 中使用 ViewModel。

      因此您可以在代码中使用 ViewModel 而不必使用线程来处理它:

      viewModel.getAllDrinks.observe(this, Observer { drinks -> adapter.updateData(drinks)}
      

      在这里您也可以更新您的视图。

      【讨论】:

      • OP 实际上并没有说他们拥有(或知道)什么是视图模型,因此您也应该在答案中包含该解释和代码:) 此外,您所描述的内容可能是 liveData 而不是 ViewModel
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多