【问题标题】:Kotlin & Anko coroutines: return outside asyncKotlin 和 Anko 协程:异步返回
【发布时间】:2018-02-22 03:18:21
【问题描述】:

在我们的项目中,我们需要在进行操作之前获取一些数据(这些数据将被存储)。如果数据是在 15 分钟前获得的,我们必须刷新它。

我们正在使用 Kotlin + Anko 协程来做到这一点。这个想法(假设数据是在之前的某个时间获得的)是:

该方法被调用并检查我们何时获得数据。 如果小于 15 分钟前,则返回它。 如果没有,则异步获取(是网络操作),存储并返回。

由于在获取刷新数据之前我们无法进行任何操作,因此刷新必须是同步的(尽管网络操作本身是异步的)。

我们有这个代码:

fun Context.retrieveInfo(api: Api?): User? {

  try {

    // For sake of simplification the real conditional check is removed
    if (time > 15) {

        val context = this
        val asyncUser = async(UI) {
            val obtainData: Deferred<Data?> = bg {
                api?.obtainData(sphelper.getDefaultUser(context))
            }

            val obtainedData = storeAndRetrieve(obtainData.await(), context)
            return@async obtainedData
        }

 // ???????

    } else {
        val input = ObjectInputStream(this.openFileInput("data.dat"))
        return input.readObject() as Data
    }
  } catch (e: Exception) {
    return null
  }
}

我们如何让函数在 async(UI) 块之外等待结果?需要返回,但我们不知道应该放什么。我们已经尝试过使用 Deferred 对象 (return asyncUser.getCompleted()) 的 getCompleted() 方法,但它最终会崩溃,因为它返回 null。

谢谢!

【问题讨论】:

    标签: android kotlin anko


    【解决方案1】:

    我看到了几种方法来做到这一点。一种是使用kotlinx.coroutines.experimental方法runBlocking

    val user = runBlocking(CommonPool) {
        val asyncUser = async(UI) {
            val obtainData: Deferred<String> = bg {
                ...
            }
    
            val obtainedData = storeAndRetrieve(obtainData.await(), context)
            return@async obtainedData
        }
        return@runBlocking asyncUser.await()
    }
    

    根据用例,您甚至可以将其简化为:

    val asyncUser = runBlocking {
        async(CommonPool) {
            val obtainedData = storeAndRetrieve(api?.obtainData(sphelper.getDefaultUser(context)), context)
            return@async obtainedData
        }.await()
    }
    

    另一种方法是使用基本的Java CountDownLatch

    var asyncUser: String? = null
    val c = CountDownLatch(1)
    async(UI) {
        val obtainData: Deferred<String> = bg {
            ...
        }
    
        val obtainedData = obtainData.await()
        asyncUser = obtainedData
        c.countDown()
    }
    c.await()
    

    【讨论】:

    • 我已经尝试过简化版和 CountDownLatch,两者都很好用。谢谢!
    • 我读到 runBlocking 是用于测试目的,不适合最终产品。
    猜你喜欢
    • 2016-09-30
    • 1970-01-01
    • 2019-01-15
    • 2022-01-18
    • 1970-01-01
    • 2018-01-25
    • 2019-02-21
    • 2021-11-12
    • 1970-01-01
    相关资源
    最近更新 更多