同时使用Flow和CoroutineScope的Dispatchers.IO会遇到麻烦吗?

问题描述 投票:0回答:1

为了避免在主线程中进行繁重的工作,我在

.flowOn(Dispatchers.IO)
中申请了
listIncompleted
的Flow
class 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
线程中运行。

kotlin kotlin-coroutines flow
1个回答
2
投票

使用

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
在内部修复它。

© www.soinside.com 2019 - 2024. All rights reserved.