我有一个用例,我想使用协程,但是如何实现它却有些困惑。
具有范围并绑定到UI生命周期并从存储库调用API的ViewModel:
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()
}
}
存储库使用协程构建网络调用,如下所示:
suspend fun getUser() = GlobalScope { ... }
用例是,一旦从ViewModel调用了API,就必须始终完全执行存储库功能,因为我们需要捕获服务器的所有网络响应。
如何确保始终执行存储库中的协程,但ViewModel协程将被取消以避免一旦清除视图模型后发生内存泄漏?
根据GlobalScope
I的文档,我认为可以始终执行使用全局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"
}
}
另外,我们可以减少showUser()
功能:
fun showUser() = repo.getUser().then(this) {
// `it` contains the result
// here is the main thread, use `it` to update UI
}
使用扩展功能then
:
fun <T> Deferred<T>.then(scope: CoroutineScope = GlobalScope, uiFun: (T) -> Unit) {
scope.launch { uiFun([email protected]()) }
}
如果您是为Android开发的,并且希望确保在清理ViewModel之后甚至完全执行了IO操作,请使用WorkManager。它旨在用于异步和可延迟任务,这些任务需要保证即使应用程序退出,系统也将运行它们。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句