为了避免在主线程中进行繁重的工作,我在
.flowOn(Dispatchers.IO)
中申请了listIncompleted
的Flowclass TranslateIncompleted
。
你知道的,有时当其他用户调用挂起功能时,他在
CoroutineScope(Dispatchers.IO) .launch {...}
内调用它。
1:
Dispatchers.IO
Flow
和 CoroutineScope
都会遇到麻烦吗?
2:如果我只能使用一个,那么使用
Flow.flowOn(Dispatchers.IO)
和使用 CoroutineScope(Dispatchers.IO)
哪种方式更好?
class ServiceTranslate: Service() {
@Inject lateinit var translateIncompleted: ITranslateIncompleted
private var job: Job? = null
override fun onCreate() {
super.onCreate()
job = CoroutineScope(Dispatchers.IO) .launch {
translateIncompleted.translateIncompletedAndUpdate()
}
}
override fun onDestroy() {
super.onDestroy()
job?.cancel()
}
...
}
class TranslateIncompleted @Inject constructor(
...
): ITranslateIncompleted {
override suspend fun translateIncompletedAndUpdate() {
val listIncompleted = handleMInfo.listIncompleted()
listIncompleted
.flowOn(Dispatchers.IO)
.collect {
...
}
}
}
新增内容:
致Tenfour04:谢谢!
A:我对我的代码做了一些修改。现在好看吗?
B:我不相信
onEach
是块函数,但 collect
是。我希望收集在流程变化时继续运行和处理数据。由于onEach
只运行一次,我认为它不适合这种特殊情况,对吗?
C:为什么在流程上指定
Dispatchers.IO
是一个糟糕的设计?如果我在 Flow 上指定 Dispatchers.IO,无论调用 Flow 的什么方法,我都可以保证在 Dispatchers.IO
线程中运行。
使用
CoroutineScope(…).launch
是一种代码味道,因为如果您不打算将其分配给属性,则不应创建新的协程范围,以便您可以在适当的时间取消它。 (您可以将返回的 Job 分配给您在适当的时候取消的属性,但是您也可以使用 GlobalScope。)
如果您使用 LifecycleService 而不是 Service 作为您的超类,那么您可以使用
lifecycleScope
来启动协程。但如果你不这样做,你应该创建一个带有 SupervisorJob 的 CoroutineScope 并在onDestroy()
中取消它。
如果你正在启动一个协程,无论你的应用程序在什么屏幕或服务中,都不能取消,那么你可以使用 GlobalScope,但你必须小心,不要捕获对可能是内存泄漏的东西的引用.
很少需要在从其他地方获得的流上指定 Dispatchers.IO。如果其他类公开共享阻塞的流,那将是非常糟糕的设计并且违反惯例。据我所知,Android、Google 或 Square 库都没有这样做。您唯一应该使用
flowOn
的地方是在您自己的 blocking 代码added 到 Flow 运算符中的 Flow 之后,就像在 onEach
块中一样。
通常,如果我在协程中所做的只是收集一个流,那么我根本不会使用
launch
。您可以在流程中使用 onEach
和 launchIn
以获得更清晰的语法。
——- 编辑:
A) 现在看起来没问题,因为您确保在
onDestroy
中取消了作业。您可以通过使用 val
CoroutineScope 属性而不是 var
作业来使其更容易防错吗?财产。但是没有必要指定一个调度程序,因为你的协程唯一做的就是调用一个挂起函数。
B) 我不知道你到底想说什么。
onEach
是运算符。它不会阻塞或暂停,但您传递给它的 lambda 会暂停,并且会针对每个上游排放重复调用,就像传递给 collect
的 lambda 会针对每个上游排放重复调用。您不得在 onEach
中调用阻塞代码,除非您在它后面加上 flowOn
。 collect
也不会阻塞。它暂停。
C) 那不是我说的。我说过你应该能够假设从另一个类检索到的流不会阻塞,因为如果它阻塞了,那么另一个类的设计者就是在为你设置一个打破惯例的陷阱。如果您是创建流以传递给其他类的类的设计者,那么您知道您的阻塞代码在哪里以及哪个调度程序是合适的,因此您可以在与其他类共享之前使用
flowOn
在内部修复它。