【问题标题】:'Inappropriate blocking method call' - How to handle this warning on Android Studio“不适当的阻塞方法调用” - 如何在 Android Studio 上处理此警告
【发布时间】:2021-03-19 20:59:15
【问题描述】:

我已经编写了这段代码 sn-p 来将图像文件从 Firebase 存储下载到本地存储。

contentResolver.openOutputStream(uri)?.use { ops ->   // *
    Firebase.storage.getReferenceFromUrl(model.mediaUrl).stream.await().stream.use { ips ->
        val buffer = ByteArray(1024)
        while (true) {
            val bytes = ips.read(buffer)   // *
            if (bytes == -1)
                break
            ops.write(buffer, 0, bytes)   // *
        }
    }
}

在标记的行中,android studio 给我Inappropriate blocking method call 警告,突出显示 openOutputStream()、read() 和 write() 函数。我已经运行了几次代码并且它运行正常。整个代码 sn-p 在一个挂起函数中,从 IO CoroutineScope 调用。
有人请告诉我此警告的实际原因和解决方案。

编辑此代码在以下上下文中调用。

fun someFunc() {
    lifecycleScope.launch(IO) {
        val uri = getUri(model)
        ...
    }
    ...
}
...
suspend fun getUri(model: Message): Uri {
    ... // Retrive the image file using mediastore.
    if ( imageNotFound ) return downloadImage(model)
    else return foundUri
}
suspend fun downloadImage(model: Message): Uri {
    ... // Create contentvalues for new image.
    val uri = contentResolver.insert(collectionUri, values)!!
    // Above mentioned code snippet is here.
    return uri
}

【问题讨论】:

  • 请显示此代码的更多上下文,以便我们了解它是如何在 IO 调度程序上调用的。顺便说一句,没有理由在use 的目标上调用close()
  • @Tenfour04 更多上下文意味着什么?您是否希望我编辑帖子以添加调用此函数的代码。
  • 是的,围绕此代码或调用此代码的代码。或者整个挂起函数。
  • @Tenfour04 刚刚添加了初始代码的上下文。现在看看有没有帮助。

标签: android kotlin inputstream kotlin-coroutines outputstream


【解决方案1】:

正确组合的挂起函数永远不会阻塞。它不应该依赖于从特定的调度程序调用,而是应该在适当的调度程序中显式包装阻塞代码。

因此,调用阻塞代码的挂起函数部分应包含在withContext(Dispatchers.IO){} 中。然后调用它的协程甚至不需要指定调度程序。这使得使用 lifecycleScope 调用函数和更新 UI 非常方便,无需担心调度程序。

例子:

suspend fun foo(file: File) {
    val lines: List<String> = withContext(Dispatchers.iO) {
        file.readLines()
    }
    println("The file has ${lines.size} lines.")
}

【讨论】:

  • 好的.. 但是如果挂起函数必须返回一些东西,那么整个函数体不能用 withContext{} 包装。在这种情况下,调用站点必须决定使用适当的调度程序调用此函数。
  • 这不是真的。 withContext 返回结果。
  • 哦,是的.. 它有效.. 谢谢。 :) 但这会使代码更加嵌套!
  • 在大多数情况下,它在呼叫站点的嵌套较少,因为您不必来回更改调度程序。对于不需要多个调度程序的挂起函数,没有嵌套,因为您可以对函数使用= withContext 语法。
猜你喜欢
  • 2020-12-20
  • 2020-04-22
  • 2020-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多