簡體   English   中英

使用協同程序更新UI異步調用

[英]Update UI async call with coroutines

我必須通過對房間數據庫的異步調用來更新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()
}

// ProductDao.kt

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

我需要的是通過我的ProductProvider更新我的UI,因為我將用於所有我需要可靠解決方案的實體。

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

要使用Dispatchers.Main導入:

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

您應該使用IO協程從Room中取出,並切換到Main(UI)協程以更新視圖。

嘗試:

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

確保安裝了Android Coroutine庫,以便Main Dispatcher正確識別Android主線程。

api "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()
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM