Retrofit response.errorBody.string() 警告我在挂起函数中调用不适当的阻塞方法
Retrofit response.errorBody.string() gives me warning of inappropriate blocking method call in suspend function
我正在开发一个 Android 应用程序。
我正在使用 Retrofit2 和 Coroutine 从我的 Rest 获取一些数据 API。
当我的 Rest API 中抛出异常时,return 异常代码和异常消息的 HTTP 状态 = 4xx 或 5xx,如下面的屏幕截图
如果响应是异常,那么我会按照下面的代码将 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 时,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
class,它有 getResult()
,其中 errorBody.string
被称为
正如你在上面的截图中看到的,唯一没有给我警告的协程是最后一个
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 和 return 它。如果我
CoroutineScope
或 GlobalScope
那么我将 return null 除非我使用 scope.join
。那么我不应该使用 coroutineScope() 吗,它使用 parent/caller 的协程作用域来实现结构化并发?
- 看起来 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
上下文中适当地执行它。不过在这个函数上,也出现了warning,不过我们知道我们处理的很好,所以可以抑制它。
@Suppress("BlockingMethodInNonBlockingContext")
suspend fun ResponseBody.stringSuspending() =
withContext(Dispatchers.IO) { string() }
所以我们确定 ResponseBody.string()
将在 IO
上下文中执行,无论它是否可能被另一个上下文包裹:
Gson().fromJson(response.errorBody()?.stringSuspending(), ExceptionResponse::class.java)
我正在开发一个 Android 应用程序。
我正在使用 Retrofit2 和 Coroutine 从我的 Rest 获取一些数据 API。
当我的 Rest API 中抛出异常时,return 异常代码和异常消息的 HTTP 状态 = 4xx 或 5xx,如下面的屏幕截图
如果响应是异常,那么我会按照下面的代码将 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 时,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
class,它有 getResult()
,其中 errorBody.string
被称为
正如你在上面的截图中看到的,唯一没有给我警告的协程是最后一个
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 和 return 它。如果我
CoroutineScope
或GlobalScope
那么我将 return null 除非我使用scope.join
。那么我不应该使用 coroutineScope() 吗,它使用 parent/caller 的协程作用域来实现结构化并发?
- 看起来 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
上下文中适当地执行它。不过在这个函数上,也出现了warning,不过我们知道我们处理的很好,所以可以抑制它。
@Suppress("BlockingMethodInNonBlockingContext")
suspend fun ResponseBody.stringSuspending() =
withContext(Dispatchers.IO) { string() }
所以我们确定 ResponseBody.string()
将在 IO
上下文中执行,无论它是否可能被另一个上下文包裹:
Gson().fromJson(response.errorBody()?.stringSuspending(), ExceptionResponse::class.java)