使用协程更新 UI 异步调用



我必须通过对房间数据库的异步调用来更新UI,但是当我这样做时,我遇到了此错误:android.view.ViewRootImpl$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触摸其视图。

FavoritesPresenter.kt

GlobalScope.launch {
    favoritesView.showFavorites(ProductProvider.getAllProducts() as ArrayList<Product>)
}

ProductProvider.kt

fun getAllProducts() : MutableList<Product> {
    return dao.getAllProducts()
}

产品道 kt

@Query("SELECT * FROM product")
fun getAllProducts(): MutableList<Product>

我需要的是通过我的产品提供商更新我的 UI,因为我将用于我的所有实体,我需要可靠的解决方案。

应使用 IO 协程从 Room 中获取,并切换到主 (UI( 协程以更新视图。

尝试:

GlobalScope.launch(Dispatchers.IO) {
            val products = ProductProvider.getAllProducts() as ArrayList<Product>
            withContext(Dispatchers.Main) {
                favoritesView.showFavorites(products)
            }
        }

确保安装了 Android 协程库,以便主调度程序正确识别 Android 主线程。

api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"

Room 2.1(目前为 alpha 版(增加了对 Kotlin 协程的支持。您可以执行以下操作:

  1. ProductDaoProductProvider中的函数标记为挂起

    // ProductDao.kt
    @Query("SELECT * FROM product")
    suspend fun getAllProducts(): List<Product>
    // ProductProvider.kt
    suspend fun getAllProducts(): List<Product> = dao.getAllProducts()
    
  2. FavoritesPresenter中为协程创建局部作用域:

    class FavoritesPresenter {
        private var favoritesView: FavoritesView? = null
        private val provider: ProductProvider = ...// initialize it somehow
        private var job: Job = Job()
        private val scope = CoroutineScope(job + Dispatchers.Main)
        fun getProducts() {
            scope.launch {
                favoritesView?.showFavorites(provider.getAllProducts())
            }
        }
        fun attachView(view: FavoritesView) {
            this.favoritesView = view
        }
        fun detachView() {
            job.cancel() // cancel the job when Activity or Fragment is destroyed
            favoritesView = null
        }
        interface FavoritesView {
            fun showFavorites(products: List<Product>)
        }
    }
    
  3. ActivityFragment中使用FavoritesPresenter

    class MainActivity : AppCompatActivity(), FavoritesPresenter.FavoritesView {
        lateinit var presenter: FavoritesPresenter
        override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)
           // ...
           presenter = FavoritesPresenter()
           presenter.attachView(this)
           presenter.getProducts()
        }
        override fun onDestroy() {
            presenter.detachView()
            super.onDestroy()
        }
        override fun showFavorites(products: List<Product>) {
            // use products to update UI
        }
    }
    

要使用调度程序.主导入:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'

最好不要使用 GlobalScope,而是使用您自己的 CoroutineContext,例如:

class YourActivity : CoroutineScope {
    private lateinit var job: Job
    // context for io thread
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.IO + job
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    job = Job()
  }
    fun toDoSmth() {
        launch {
            // task, do smth in io thread
            withContext(Dispatchers.Main) {
              // do smth in main thread after task is finished
            }                  
        }
    }
   override fun onDestroy() {
      job.cancel()
      super.onDestroy()
   }
}

相关内容

  • 没有找到相关文章

最新更新