【问题标题】:Coroutines: run a Deferred on a specific CoroutineContextCoroutines:在特定的 CoroutineContext 上运行 Deferred
【发布时间】:2019-01-17 22:17:51
【问题描述】:

我正在尝试在 Android 应用中使用 Kotlin Coroutines,特别是我已经导入了 Kotlin Coroutine Adapter for Retrofit

Kotlin Coroutine Adapter 更改 Retrofit 接口以返回 Deferred<T> 而不是 Call<T>

我不明白的是如何在我想要的特定CoroutineContext 中启动这个Deferred。考虑以下代码:

class MyViewModel @Inject constructor( private val foo: Foo, @Named("ui") private val uiContext: CoroutineContext, @Named("network") private val networkContext: CoroutineContext ) : ViewModel() { fun performSomeJob(param: String) { launch(uiContext) { try { val response = foo.bar(param).await() myTextView.setText(response.name) } catch (error: Throwable) { Log.e(error) } } }

foo.bar(param) 返回Deferred<SomeModel>

此代码有效,但我不确定 CoroutineContext 这个 foo.bar(param) 正在执行什么 (CommonPool??)。

如何明确指定我希望foo.bar(param)networkContext 中执行?

val response = async(networkContext) { foo.bar(param) }.await()

此代码不起作用,因为response 被评估为Deferred<SomeModel> 而不是SomeModel(我想要实现)。

【问题讨论】:

    标签: android kotlin retrofit retrofit2 kotlin-coroutines


    【解决方案1】:

    foo.bar() 调用不会启动另一个协程,它只是包装原生 Retrofit Call,以便其状态更改传播到 Deferred。 Retrofit 管理自己的线程来执行它的操作,这就像没有协程包装器一样工作。如果您有特定的问题,您可以通过按常规方式配置 Retrofit 来管理它。

    对你来说唯一重要的是你的协程是在 UI 上下文中执行的。

    【讨论】:

    • 那么单元测试呢?以前(使用 Rx 方法时)我们可以将调度程序指定为trampoline(),这导致我们的测试代码在同一个线程上运行。现在这段代码的可测试性如何?难道我们没有协程这样的能力吗?
    • 究竟是什么调度程序?不是调度器在网络调用完成后接管,恢复协程吗? trampoline() 在我看来就像 runBlocking()
    • 使用 Rx 方法有 foo.bar().subscribeOn(bgScheduler).observeOn(uiScheduler)。这些调度程序是由 DI 框架注入的。对于测试代码,这些依赖项作为trampoline() 调度程序提供,而不是更改线程,而是在调用线程上执行作业。至于这个例子,因为我无法指定在哪个CoroutineContext 上执行后台作业,所以我无法在测试中获得顺序代码执行行为,或者您是否声称runBlocking() 是正确使用的函数?
    • runBlocking() 将在调用线程上启动一个事件循环,因此它成为协程上下文。它会在其协程完成时完成。无论如何,只要您在等待它们之前不进行多次调用,Retrofit 代码的执行将是连续的。
    猜你喜欢
    • 2019-04-24
    • 2017-12-01
    • 1970-01-01
    • 2020-09-08
    • 1970-01-01
    • 1970-01-01
    • 2019-03-12
    • 1970-01-01
    • 2014-03-26
    相关资源
    最近更新 更多