android - 使用具有自定义范围和视图生命周期的 kotlin 协程进行轮询
问题描述
我只是从Kotlin
协程开始。我正在尝试使用协程轮询服务器,并希望在暂停Activity
或Fragment
暂停时停止轮询并相应地恢复轮询。所以 mypollScope
的生命周期比ViewModel.viewModelScope
. 我对目前的实现并不完全满意,有几个问题:
- 这是正确的创建方式吗
pollScope
?我希望它在取消时viewModelScope
也取消,这就是我指定父作业的原因。 onResume()
如果我取消pollJobs
使用,为什么协程不会启动coroutineContext.cancel()
?如果我保留一份工作清单并取消它们,它们就会开始正常工作。- 这是整体正确的方法吗?有没有更好的办法?
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.spruce.messenger.utils.FullLifecycleObserverAdapter
import kotlinx.coroutines.*
import java.io.IOException
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.coroutines.CoroutineContext
suspend fun poll(initialDelay: Long = 5000,
maxDelay: Long = 30000,
factor: Double = 2.0,
block: suspend () -> Unit) {
var currentDelay = initialDelay
while (true) {
try {
try {
block()
currentDelay = initialDelay
} catch (e: IOException) {
currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay)
}
delay(currentDelay)
yield()
} catch (e: CancellationException) {
break
}
}
}
class MyDataModel : ViewModel() {
val pollScope = CloseableCoroutineScope(SupervisorJob(parent = viewModelScope.coroutineContext[Job]) + Dispatchers.Main)
private val pollJobs = CopyOnWriteArrayList<Job>()
inner class CloseableCoroutineScope(context: CoroutineContext) : FullLifecycleObserverAdapter(), CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
// coroutineContext.cancel() cancels it but then coroutine doesn't start again in onResume() thats why cancelling jobs instead
pollJobs.forEach { it.cancel() }
}
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
refresh()
}
}
fun refresh() {
if (pollJobs.count { it.isActive } == 0) {
startPoll()
}
}
private fun startPoll() = pollScope.launch {
try {
poll {
//fetch data from server
}
} catch (e: Exception) {
//ignore
}
}.also {
track(it)
}
private fun track(job: Job) {
pollJobs.add(job)
job.invokeOnCompletion {
pollJobs.remove(job)
}
}
}
然后在我的片段中添加 pollScope 作为生命周期观察者viewLifecycleOwner.lifecycle.addObserver(viewModel.pollScope)
。
解决方案
你
pollScope
对我来说似乎很好。当您取消 a
Job
时,它会取消该 的所有协程Job
。我将 a
ViewModel
与 a 一起使用CoroutineScope
,然后从中进行轮询。确保Job
在 VM 死机时管理我的协程并取消我的协程。
class MyViewModel() : ViewModel(),
CoroutineScope by CoroutineScope(Dispatchers.Main + SupervisorJob()) {
// ...
override fun onCleared() {
cancel()
super.onCleared()
}
}
推荐阅读
- javascript - React-Native 应用程序上的 AppLock 功能
- flutter - 使用 Dart 将字符串转换为列表/映射
- javascript - NodeJS (Express + PUG) MVC 端口检查器
- java - 创建一个编码字母
- r - R中的函数可以计算一个数字在向量中出现的次数
- esp8266 - AT+CIPSENDEX 返回链接无效
- c# - 如何在 Linq Where 子句中利用动态编程?
- android - 为什么我的应用程序在集成 Flutter 的 webview 后崩溃。获取平台异常
- c# - 等待动态获取错误“System.ValueType”不包含“GetAwaiter”的定义
- firebase - 相同的 Flutter Web 构建使用 `dhttp` 在本地运行,但使用 `firebase serve` 或 `firebase deploy` 失败