android - 改造 response.errorBody.string() 给了我暂停函数中不适当的阻塞方法调用的警告

标签 android api kotlin retrofit2 coroutine

我正在开发一个 Android 应用程序。
我正在使用 Retrofit2 和 Coroutine 从我的 Rest API 中获取一些数据。
当我的 Rest API 中抛出异常时,它会返回异常代码和异常消息,其中 HTTP 状态 = 4xx 或 5xx,如下面的屏幕截图所示
enter image description here
如果响应是异常,则根据以下代码将 exceptionCode 和 exceptionMessage 映射到我的 Android 应用程序中的响应。

val exceptionBody = Gson().fromJson(response.errorBody()?.string(), ExceptionResponse::class.java)
这是ExceptionResponse类(class)
data class ExceptionResponse(
    val exceptionCode: String,
    val exceptionMessage: String
)
这是一个问题。当我做 response.errorBody()?.string() ,Android Studio 给我一个警告说“不适当的阻塞方法调用”
这是我的repository调用网络调用
override fun fetchData() {
    CoroutineScope(Dispatchers.IO).launch {
        val fetchedData = myRemoteDataSource.fetchData()
    }
}
这里是 MyRemoteDataSource类(class)
class MyRemoteDataSourceImpl(
    private val myAPIService: MyAPIService
): BaseRemoteDataSource(), MyRemoteDataSource {

    override suspend fun fetchData(): Resource<List<Data>> {
        return getResult {
            myAPIService.fetchData()
        }
    }
}
这是我的BaseRemoteDataSource具有 getResult() 的类在哪里 errorBody.string叫做
enter image description here
正如您在上面的屏幕截图中看到的那样,唯一没有给我警告的协程是最后一个
GlobalScope.launch(Dispatchers.IO) {
    Gson().fromJson(response.errorBody()?.string(), ExceptionResponse::class.java)
}
所以我对这个警告和 coroutineScope 有几个问题
  • 为什么最后一个没有给我警告,而是所有其他协程范围?
  • GlobalScope.launch(Dispatchers.IO) {
        Gson().fromJson(response.errorBody()?.string(), ExceptionResponse::class.java)
    }
    
  • 似乎我需要结构化并发,因为我需要解析 JSON 并返回它。如果我 CoroutineScopeGlobalScope那么我将返回 null 除非我使用 scope.join .那么我不应该使用使用父/调用者的协程范围进行结构化并发的 coroutineScope() 吗?
  • 看起来 response.errorBody()?.string() 正在解析应该在 Dispatchers.Default 中的 JSON,不是吗?仅供引用,我附上了 string() 的源代码
  •   public final String string() throws IOException {
        try (BufferedSource source = source()) {
          Charset charset = Util.bomAwareCharset(source, charset());
          return source.readString(charset);
        }
      }
    
  • 使用最后一个是否可以,因为那时我正在 CoroutineScope 中创建 GlobalScope。
  • withContext() 是否像 coroutineScope() 一样使用调用者的协程范围,还是使用不同的调度程序创建一个新范围?

  • 很抱歉一次转储问题,但它们都是相关的。感谢你们!!!

    最佳答案

    IO 中调用阻塞执行是正常的。上下文,因为它旨在执行此类任务。所以我认为最好的方法是在 ResponseBody 上写一个扩展函数。在 IO 中进行操作上下文适当。但是,在这个函数上,也出现了警告,但我们知道我们处理得很好,我们可以抑制它。

    @Suppress("BlockingMethodInNonBlockingContext")
    suspend fun ResponseBody.stringSuspending() =
        withContext(Dispatchers.IO) { string() }
    
    所以我们确信ResponseBody.string()将在 IO 中执行上下文,无论它可能被另一个上下文包装:
    Gson().fromJson(response.errorBody()?.stringSuspending(), ExceptionResponse::class.java)
    

    关于android - 改造 response.errorBody.string() 给了我暂停函数中不适当的阻塞方法调用的警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64190661/

    相关文章:

    android - 从 firebase 中删除项目而不会使应用程序崩溃

    api - 使用亚马逊(产品广告)API 禁用加入按钮

    api - 使用 Github API 获取文件差异

    android - 跳过 CSV 解析器中的每第 N 行

    java - Kotlin:在 for 循环中创建内部类中所有日期的列表。从日期列表中查找最新日期

    kotlin - Gradle Kotlin JS插件-无法生成装饰类

    android - Android 上的图像需要多大的图像才能使图像看起来非常好?

    android - 设计开关的样式

    android - 错误 :SSL peer shut down incorrectly In Android studio 3. 0.1

    rest - 使用RESTful服务和应用程序API实现SOA?