为什么
似乎在使用Coroutines中使用调度员会感到困惑。调度员被用来提及Coroutine应在的线程。
-
Dispatchers.Main
-主线程 -
Dispatchers.IO
-IO线程 -
Dispatchers.Default
-CPU密集型线程
虽然我们应该根据功能的工作来提及Coroutine的调度员,但我们不需要为暂停功能的呼叫者做同样的事情。即,实际工作的悬浮函数处理要使用的调度程序,并且该功能的呼叫者不必担心。
实际上,各种库明确为长期封锁操作提供了暂停的API。将适当的任务移至背景线程的复杂性已经在库中得到照顾。拨打库的暂停API时,不必考虑它。
p.s:不建议在生产代码中使用Dispatchers.Unconfined
,也不建议在此处讨论。
该怎么办
- 当您编写长期运行或CPU密集任务时,请使用适当的调度程序包装代码,以便函数的呼叫者不必担心。
- 如果图书馆提供暂停API,则图书馆将照顾调度员。 (这是一个很好的做法,最好检查库的文档以查看是否提供暂停API)
- 如果您要调用现有的暂停功能,请检查它是否使用适当的调度程序。如果没有
怎么做
这是一个示例:
fun onDoneClicked() {
viewModelScope.launch(Dispatcher.IO) {
initiateSeeding()
}
}
...
suspend fun initiateSeeding() {
async {
// Do some work that runs in IO thread
}
}
-
用
Dispatcher.IO
包装长期运行的IO任务
suspend fun initiateSeeding() { async(Dispatcher.IO) { // Do some work that runs in IO thread } }
-
从函数的呼叫者中删除调度员
fun onDoneClicked() { viewModelScope.launch { initiateSeeding() } }
另一个很好的例子是改造。 Raturofit为网络调用提供了暂停的API。图书馆照顾调度员,该功能的呼叫者不必担心。
interface SeedApiService {
@GET("seeds")
suspend fun getSeeds(): List<Seed>
}
class SeedRepository(private val seedApiService: SeedApiService) {
suspend fun getSeeds(): List<Seed> = seedApiService.getSeeds()
}
class SeedViewModel(private val seedRepository: SeedRepository) {
fun fetchSeeds() {
viewModelScope.launch {
try {
val seeds = seedRepository.getSeeds()
// Do something with the seeds
} catch (e: Exception) {
// Handle error
}
}
}
}
库将处理调度员,我们不需要在viewModelScope.launch
函数中提及它。
参考
- Retrofit Suspended Functions
- Do-i-need-to-call-suspend-functions-of-retrofit-and-room-on-a-background-thread