协程、调度程序和不适当的阻塞方法



我写了一个应用程序,基本上做了很多IO响应用户提示。它似乎工作得很好,但Android Studio抱怨它所有的IO方法调用都是"不适当的阻塞方法"。

我尝试遵循官方建议(这里和这里),所以我使用协程并将我所有的IO调用包装在withContext(Dispatchers.IO)中,但Android Studio仍然坚持认为它们都是"不适当的阻塞方法"。

最小可复制示例(见这里):

package com.example.blockingtest
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.FileInputStream
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
CoroutineScope(Dispatchers.Main).launch { mySuspendFunction() }
}
private suspend fun mySuspendFunction() {
withContext(Dispatchers.IO) { FileInputStream("dummy.txt") }
}
}

Android Studio将FileInputStream调用标记为"不合适的阻塞方法"。

我在Stack Overflow和其他地方发现了很多关于这类事情的讨论,但没有正确的解决方案或令人满意的解释:

  • 这个公认的Stack Overflow答案要么是错误的,要么是过时的,因为它的作者在编辑中承认。
  • 这个堆栈溢出答案,这个,这个接受的一个(在编辑中),这个接受的一个都断言withContext(Dispatchers.IO)包装是解决方案;它不能阻止Android Studio的警告,如上所述。
  • 这个Stack Overflow的答案和这个断言问题是有问题的方法可以抛出异常,但是没有真正的解释为什么这种可能性应该触发一个"不适当的阻塞方法";警告。此外,一个建议是将调用包装在runCatching {}中。这确实阻止了Android Studio的抱怨,但正如其中一个评论所指出的,经典的try / catch语义并没有帮助。我完全不明白。
  • 有人建议抑制警告。我想要一个真正的解决方案或解释。
  • 另一个堆栈溢出讨论,没有真正的解决方案,另一个,也没有工作的解决方案。
  • 其他讨论:这里,这里。没有解决方案/解释Android Studio的行为,我注意到。

Android Studio在这一领域是否就像一些人在相关讨论中断言的那样严重失败?多年来,我发现每当我认为工具有问题时,那肯定是我的错,但这真的是Android Studio的问题吗?

FileInputStream(..)是一个线程阻塞函数,你对它无能为力。在withContext(Dispatchers.IO)中调用它确实是作为Dispatchers处理它的正确方法。IO可以有无限数量的实际线程(由硬件或ART限制)。因此,如果一个线程被阻塞,协程可以在另一个线程中运行。

如果问题是在您在withContext(Dispatchers.IO)中包装调用后的警告,那么您唯一可以做的就是抑制它或等待Kotlin更新,IDE将正确识别您已经按照预期处理了调用。

最新更新