【问题标题】:Kotlin: structure for sequential coroutinesKotlin:顺序协程的结构
【发布时间】:2019-02-19 18:35:31
【问题描述】:

我正在为 Android 构建一个库管理器应用程序,并尝试构建一个视图来显示从当前集合到根目录的“集合”(即文件夹)的层次结构。

数据库是用 Room 实现的(通过 collectionRepo 间接访问)。每个 Collection 对象都有一个唯一的键并且知道它的父键。

我想做什么:

  1. 给定当前集合的键,构建集合层次结构 直到根。
  2. 完成后,构建一个 UI 渲染 层次结构。

对于 Kotlin 的协程,这似乎应该很简单,但我无法正确构建协程。

由于对collectionRepo.getCollection(curKey) 的每次调用最终都会执行Room db 查询,因此它必须脱离主线程。但是我需要等待查询返回才能知道后续查询所需的 parentKey。

private suspend fun buildBackstackView() {

    var curKey = collectionViewModel.getCurrentCollectionKey()

    coroutineScope {
        launch {
            do {
                val curCollection = when (curKey) {
                    "" -> {
                        Collection("", 0, "TOP", "") // collection's parent is root - create a fake root Collection to push to the stack
                    }
                    else -> {
                        collectionRepo.getCollection(curKey) // ultimately a Room database query
                    }
                }

                collectionStack.add(curCollection)
                curKey = curCollection.key

            } while (curKey != "")
        }
    }

    withContext(Dispatchers.Main) {

        ...build UI view using collectionStack...

    }
}

为了响应 Sergey 的请求,collectionRepo.getCollection() 只是将请求传递给定义 Room 查询的 DAO 方法。

@Query("SELECT * FROM collections WHERE `key` = :colKey LIMIT 1")
fun getCollection(colKey: String): Collection

【问题讨论】:

标签: android kotlin android-room kotlinx.coroutines kotlin-coroutines


【解决方案1】:

请检查下一个代码,它应该对你有帮助:

    // creating local scope for coroutines
    private var job: Job = Job()
    private val scope = CoroutineScope(Dispatchers.Main + job)     

    // call this to cancel job when you don't need it anymore, for example in Activity.onDestroy() method
    fun cancelJob() {
        job.cancel()
    }

    private fun buildBackstackView() {
        var curKey = collectionViewModel.getCurrentCollectionKey()

        scope.launch {
            do {
                val curCollection = when (curKey) {
                    "" -> {
                        Collection("", 0, "TOP", "")
                    }
                    else -> withContext(Dispatchers.IO) { // runs in background thread suspending the coroutine
                        collectionRepo.getCollection(curKey)
                    }

                }

                collectionStack.add(curCollection)
                curKey = curCollection.key

            } while (curKey != "")

            // ...build UI view using collectionStack...
        }
    }

要使用 Dispatchers.Main 导入:

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

【讨论】:

  • 比我更接近,但它仍然无法正常工作。 withContext(Dispatchers.IO) 似乎没有暂停协程。此代码设置了一个竞争条件,其中收集堆栈的顺序从一次执行到下一次执行是完全随机的(如果堆栈完全构建)。
  • 根据withContext()函数的文档:Calls the specified suspending block with a given coroutine context, suspends until it completes, and returns the result.它应该暂停协程。
猜你喜欢
  • 2021-07-20
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
  • 2020-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多