暂停功能不应在其他调度员上调用
#android #codequality #sonarlint #viewmodel

为什么

似乎在使用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
    }
}
  1. Dispatcher.IO包装长期运行的IO任务

    
    suspend fun initiateSeeding() {
        async(Dispatcher.IO) {
            // Do some work that runs in IO thread
        }
    }
    
  2. 从函数的呼叫者中删除调度员

    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函数中提及它。

参考