iam*_*ini 7 kotlin kotlinx.coroutines
我有一个用例,我想使用协程,但有点混淆如何实现它.
一个ViewModel,它具有一个范围并绑定到UI生命周期并从存储库调用API:
class UserViewModel(): CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
fun showUser() {
launch {
val user = repo.getUser()
livedata = user
}
}
fun onClean() {
job.cancel()
}
}
Run Code Online (Sandbox Code Playgroud)
存储库使用协同程序来构建网络调用,如下所示:
suspend fun getUser() = GlobalScope { ... }
Run Code Online (Sandbox Code Playgroud)
用例是一旦从ViewModel调用API,就需要始终完全执行存储库功能,因为我们需要捕获来自服务器的所有网络响应.
我怎样才能确保存储库中的协程始终执行,但是一旦视图模型被清除,ViewModel协程将被取消以避免内存泄漏?
根据 的文档,GlobalScope我认为我们可以相信使用全局 CoroutineScope 启动的协程始终会被执行。文档说:
全局范围用于启动顶级协程,这些协程在整个应用程序生命周期内运行并且不会提前取消。
我已经实现了一些测试代码,当在存储库中的协程job内取消时UserViewModel,它继续执行。这是带有我的评论的代码:
class UserViewModel(): CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
fun showUser() {
launch {
val repo = Repository()
val userDeferred = repo.getUser()
// if onClean() is called before the coroutine in Repository finishes,
// this line will not be called, but coroutine in Repository will continue executing
val result = userDeferred.await() // wait for result of I/O operation without blocking the main thread
}
}
fun onClean() {
job.cancel()
}
}
class Repository {
fun getUser() = GlobalScope.async {
delay(4000)
// this line is executed no matter whether the job in UserViewModel was canceled or not
"User returned"
}
}
Run Code Online (Sandbox Code Playgroud)
另外我们可以减少showUser()函数:
fun showUser() = repo.getUser().then(this) {
// `it` contains the result
// here is the main thread, use `it` to update UI
}
Run Code Online (Sandbox Code Playgroud)
使用扩展功能then:
fun <T> Deferred<T>.then(scope: CoroutineScope = GlobalScope, uiFun: (T) -> Unit) {
scope.launch { uiFun(this@then.await()) }
}
Run Code Online (Sandbox Code Playgroud)
如果您针对 Android 进行开发,并且希望确保即使在清理 ViewModel 后也能完全执行 IO 操作,请使用WorkManager。它适用于异步和可延迟的任务,这些任务需要保证即使应用程序退出,系统也会运行它们。
| 归档时间: |
|
| 查看次数: |
638 次 |
| 最近记录: |