Kotlin Coroutines viewModelScope 中的改造调用

Posted

技术标签:

【中文标题】Kotlin Coroutines viewModelScope 中的改造调用【英文标题】:Retrofit call in Kotlin Coroutines viewModelScope 【发布时间】:2020-07-27 16:02:18 【问题描述】:

最近我更新了我的ViewModel 以使用新的viewModelScope。从它的实现中,我看到Dispatchers.Main.immediate 被设置为viewModelScope 的默认CoroutineDispatcher

因此,当在viewModelScope.launch 中打印当前的Thread 时,它会给出Thread[main,5,main]

但这是我的问题。虽然这在主线程中运行,但以下代码对我来说是有效的,它执行网络调用。

viewModelScope.launch 
    userRepo.login(email, password)

这里userRepo.login(email, password)suspend函数,它调用Retrofitsuspend函数。

如果我的当前线程是主线程,那么它是如何工作的?

【问题讨论】:

【参考方案1】:

之所以有效,是因为 Retrofit 的 suspend 实现委托给 Call<T>.enqueue。这意味着它已经默认在自己的后台执行程序上执行,而不是使用调用者的Dispatcher

【讨论】:

如果我在 withContext(Dispatchers.IO) 块中调用这个挂起函数怎么办?它仍然在 Call.enqueue 中运行吗?如果是,那么使用 Dispatchers.IO 创建的线程没用?还有什么方法可以调试或检查 Retrofit 的实现吗?如果改造无论如何都在调用 enqueue 那么它是作为 Dispatchers.IO 的轻量级线程吗 是的,它仍然在 Okhttp 的调度程序上运行。不,创建的线程不是无用的,因为应用了正常的协程优化。查看HttpServiceMethod 类进行调试。并且使用的调度程序取决于提供给 Retrofit 的 OkHttpClient 的配置。【参考方案2】:

从主线程调用挂起函数总是安全的。但是,如果您要执行繁重的操作,例如从服务器、数据库、内容加载器中获取数据……最好使用适当的调度程序,例如 Dispatcher.IO。

如果您愿意,可以将此调度程序与 viewmodelScope 一起使用,然后所有挂起函数都使用此调度程序运行。

现在 ViewModel 是一个 Executor(一个将执行从 Main 更改为后台的类)

如果要更改 ViewModel 中的 Dispatcher,一个好的做法是通过构造函数注入此 Dispatcher 来测试 ViewModel。

【讨论】:

以上是关于Kotlin Coroutines viewModelScope 中的改造调用的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin Coroutines 中的 main-safe 是啥?

Kotlin Coroutines 的现有 3 函数回调

Kotlin Coroutines:等待多个线程完成

Kotlin Coroutines viewModelScope 中的改造调用

Kotlin Coroutines 选择 Dispatcher

如何使用 Kotlin Coroutines 在 Retrofit 中处理 204 响应?