【问题标题】:How to call a suspend function within a apply expression如何在应用表达式中调用挂起函数
【发布时间】:2021-04-02 00:12:46
【问题描述】:

我想在 apply { } 块中调用挂起函数。
我有一个:

private suspend fun retrieve(accountAction: AccountAction): Any

suspend fun login() {  
 accountEvent.apply {  
  retrieve(it)
}

我试图用suspend { retrieve(it) }runblocking { retrieve(it) } 包围它,但似乎即使它没有产生错误(只能在协程主体内调用暂停函数)代码也没有进入检索函数,而只是通过通过它,这就是我的单元测试失败的原因。

仅供参考:这是一个类,而不是一个活动或片段。

编辑:

这是实际代码(来自评论):

override suspend fun login(webView: WebView) = trackingId()       
    .flatMap { id -> AccountAction(client, id, WeakReference(webView), upgradeAccount) }
    .map {
        it.apply {       
            upgradeWebViewProgress(webView)
            suspend { retrieve(it) }  
        }
    }       
   .flatMap { updateAuth(it) }

【问题讨论】:

  • 我试过你的代码,填写了你没有提供的部分,对我来说效果很好。在apply 中挂起可以正常工作,因为它是一个内联函数。您能否提供一个最小但完整的示例来重现该问题?
  • 我删除了我的答案,因为它对您的情况没有帮助(正如@marstran 指出的那样)。请提供更详细的示例,以便我们尝试找到更好的解决方案。
  • 这是主要代码。 override suspend fun login(webView: WebView) = trackingId() .flatMap { id -> AccountAction(client, id, WeakReference(webView), upgradeAccount) }.map { it.apply { upgradeWebViewProgress(webView) suspend { retrieve(it) } } } .flatMap { updateAuth(it) }
  • 当我在单元测试中模拟检索乐趣的返回时。我得到一个值,就好像检索乐趣从未触发过一样。
  • 重新排序你的函数怎么样:fun login(webView: WebView) { val result = trackingId().flatMap { id -> AccountAction(client, id, WeakReference(webView), upgradeAccount) } upgradeWebViewProgress(webView) val retrieved = retrieve(result) return retrieved.{ updateAuth(it) } }

标签: android kotlin kotlin-coroutines suspend


【解决方案1】:

已编辑:

这显示了一个不使用 map 的替代方法,因为我对这个示例的选择并不真正需要它(除非你真的想链接你的所有调用)

suspend fun login(webView: WebView) { 
  val result = trackingId().flatMap { id -> AccountAction(client, id, WeakReference(webView), upgradeAccount) } 
  
  upgradeWebViewProgress(webView) 

  return retrieve(result).flatMap { updateAuth(it) } }

【讨论】:

  • 是的,我知道。这主要是这里的问题,但是还有其他方法吗?
  • 没有apply 也可以。为什么在这种情况下必须使用apply?我所看到的,如果accountEventAccountAction 类型,你可以调用retrieve(accountEvent)
  • 我的示例不是真实代码的 100% 副本,但我实际上是从地图乐趣中获取 accountEvent。这与应用乐趣相同。
  • 您介意展示实际的实现吗?也许这样您的问题就会变得更清楚,我们可以找到更好的解决方案。
  • @ChristianB 你仍然可以在原来的apply函数中挂起,因为它是一个内联函数。
【解决方案2】:

当您想对这样的元素列表执行异步(挂起)操作时,可以使用Flow-API。您可以在此处阅读有关该 API 的信息:https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/

让您的示例工作的最简单方法可能是将您的列表转换为Flow,执行挂起操作,然后转换回List。像这样:

override suspend fun login(webView: WebView) = trackingId()       
    .flatMap { id -> AccountAction(client, id, WeakReference(webView), upgradeAccount) }
    .asFlow()
    .map {
        it.apply {       
            upgradeWebViewProgress(webView)
            retrieve(it)
        }
    }
    .toList()
    .flatMap { updateAuth(it) }

请注意,这可能不是最有效的,因为它将按顺序执行retrieve-操作。例如,您可以在Flow 上使用其他运算符来并行执行这些操作。

【讨论】:

  • AccountAction 返回一个 Observable,因此我不能使用 asFlow() 的乐趣。或者有没有办法从 Observable 转换为 Flow ?
  • @Ape04 使用 kotlinx-coroutines-rxjava2 库进行互操作。
  • 我看过那个库。但是,我正在尝试删除此处的 rxjava 库并将其替换为协程,因此添加另一个使用它的库并没有太大的改进。
  • 那么你应该将返回 Observable 的调用改为返回 Flow。
  • 是的,我想我最终会这样做。我会努力让你更新
猜你喜欢
  • 2021-11-24
  • 1970-01-01
  • 2020-04-13
  • 1970-01-01
  • 2021-12-21
  • 2016-10-02
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多