我必须通过对房间数据库的异步调用来更新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 协程的支持。您可以执行以下操作:
-
将
ProductDao
和ProductProvider
中的函数标记为挂起:// ProductDao.kt @Query("SELECT * FROM product") suspend fun getAllProducts(): List<Product> // ProductProvider.kt suspend fun getAllProducts(): List<Product> = dao.getAllProducts()
-
在
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>) } }
-
在
Activity
或Fragment
中使用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()
}
}