Kotlin 和 Anko 协程:return 在异步之外
Kotlin & Anko coroutines: return outside async
在我们的项目中,我们需要在进行操作之前获取一些数据(这些数据将被存储)。如果数据是在超过 15 分钟前获得的,我们必须刷新它。
我们正在使用 Kotlin + Anko 协程来做到这一点。这个想法(假设数据是在之前的某个时间点获得的)是:
该方法被调用并检查我们何时获得数据。
如果不到 15 分钟前,returns。
如果不是,则异步获取它(这是一个网络操作),存储它并 return 它。
由于在获取刷新数据之前我们不能做任何事情,所以刷新必须是同步的(尽管网络操作本身是异步的)。
我们有这个代码:
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) 块之外等待结果? return 是必需的,但我们不知道应该放在那里什么。我们尝试使用 Deferred 对象的 getCompleted() 方法 (return asyncUser.getCompleted()) 但它最终崩溃了,因为它 return 为空。
谢谢!
我看到有几种方法可以做到这一点。一种是使用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()
在我们的项目中,我们需要在进行操作之前获取一些数据(这些数据将被存储)。如果数据是在超过 15 分钟前获得的,我们必须刷新它。
我们正在使用 Kotlin + Anko 协程来做到这一点。这个想法(假设数据是在之前的某个时间点获得的)是:
该方法被调用并检查我们何时获得数据。 如果不到 15 分钟前,returns。 如果不是,则异步获取它(这是一个网络操作),存储它并 return 它。
由于在获取刷新数据之前我们不能做任何事情,所以刷新必须是同步的(尽管网络操作本身是异步的)。
我们有这个代码:
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) 块之外等待结果? return 是必需的,但我们不知道应该放在那里什么。我们尝试使用 Deferred 对象的 getCompleted() 方法 (return asyncUser.getCompleted()) 但它最终崩溃了,因为它 return 为空。
谢谢!
我看到有几种方法可以做到这一点。一种是使用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()