【问题标题】:Is Task<T>.await() main-safe?Task<T>.await() 主要安全吗?
【发布时间】:2021-05-31 11:10:48
【问题描述】:

我正在编写我的第一个 Kotlin 应用程序,并且正在使用 firebase 服务进行身份验证、数据库和存储。由于无法进行原子 Firestore + Storage 操作,我发现自己正在退出回调地狱以进行简单的图像上传(带有错误回退和所有)。因此 - 我决定重构我的应用程序以使用协程。我找到了一些示例(例如herehere),但我注意到这些示例中的存储库级函数没有像android docs 中所示的withContext(Dispatchers.IO){ } 包装。他们应该吗?我猜这是两个问题合二为一:

  1. 是否应始终使用 IO 调度程序调用 Firebase 操作?
  2. kotlinx-coroutines-play-servicesTask&lt;T&gt;.await() 主安全吗?

还有一个额外的问题:我将所有 Firebase 调用包装在一个代理对象中以进行解耦 - 有没有办法将对象(/类)的所有函数设置为在相同的上下文中运行,或者我必须包装每个分别与withContext(Dispatchers.IO){ } 一起工作?

非常感谢!

【问题讨论】:

  • 按照惯例,所有挂起函数都是主安全的。可以组合一个不是的,但如果这些 await() 函数不是,那将是库作者的错误。 withContext 用于调用非挂起阻塞函数。
  • 所以我想说,按照相同的约定,我必须将所有函数编写为 main-safe 作为一个好习惯,对吧?这样做的方法是用withContext(Dispatchers.xxx) 包装每个函数,还是我误解了它的用法?
  • 在协程和挂起函数中使用withContext 来调用阻塞函数(不立即返回且不是挂起函数的函数),或者调用需要在主线程上调用的函数您目前不在主要调度员上。按照惯例,挂起函数永远不会阻塞。
  • 您的挂起功能绝对应该是主要安全的。如果您完全致力于使用协程,那么是的,您可能会将自己代码中的任何阻塞函数转换为非阻塞挂起函数,因此它们将是主安全的。
  • 我想我现在将我所有的存储库函数都转换为挂起函数。有没有办法为对象的所有函数设置上下文?

标签: android firebase kotlin kotlin-coroutines


【解决方案1】:
  1. 是否应始终使用 IO 调度程序调用 Firebase 操作?

所有 Firebase API 都是异步的,旨在从主线程安全调用,除非 API 文档中另有说明。

  1. kotlinx-coroutines-play-services 的 Task.await() 主要安全吗?

是的。正如API documentation 所说(强调我的):

等待任务完成不阻塞线程

这是suspend fun,他们不会阻止。但是,在协程之外调用它们并没有真正的意义。

【讨论】:

  • 那么我与哪个调度程序一起运行这些操作有关系吗?不算网络调用?
  • 为什么重要?如果您有疑虑,请参阅每个单独调用的 API 文档以了解其要求。我无法想象您会遇到问题,除非有一些文档另有说明。
  • It doesn't count as a network call? 我认为您在这里暗示了“所有网络调用都必须在 IO 调度程序内完成”的谬误。实际上,所有 阻塞 调用(网络或其他)都必须在不同于Main 的某个调度程序上完成(IO 不是严格要求),而suspend fun 要么是非阻塞的,要么具有严重的使其阻塞调用线程的错误。您可以放心地假设公共图书馆中的所有suspend funs 都是合规的。
  • 在 Stack Overflow 上,习惯上使用答案左侧的按钮对有用的答案进行投票并将其标记为正确。
猜你喜欢
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-04
  • 2022-08-15
  • 2020-05-03
相关资源
最近更新 更多