【问题标题】:Inappropriate blocking method call, but Suspend function 'withContext' should be called only from a coroutine or another suspend function不适当的阻塞方法调用,但挂起函数“withContext”只能从协程或另一个挂起函数中调用
【发布时间】:2021-11-03 02:08:48
【问题描述】:

在我的服务中,我需要调用onStartCommand 一些需要withContext(Dispatchers.IO) 而不是CoroutineScope(Dispatchers.IO) 的方法,例如:

  • url = URL(pokemon.linkImage)
  • url.openConnection().getInputStream()
  • fOut= FileOutputStream(file)
  • fOut.flush()
  • fOut.close()

但是Suspend function 'withContext' should be called only from a coroutine or another suspend function。因此,如果 onStartCommand 不能成为挂起函数,因为它具有覆盖,并且 withContext 不能被 CoroutineScope 调用,因为 Inappropriate blocking method call 的方法

                val url = URL(pokemon.linkImage)
                val iS = url.openConnection().getInputStream()

我该如何解决这个问题?

我的onStartCommand()

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {

    //create the directory on internal storage that will contains all pokemon images
    val path = applicationContext.filesDir.absolutePath
    val dirName = "/pokeimg"
    val dir = File(path, dirName)
    if(!dir.exists())
        dir.mkdir()
    CoroutineScope(Dispatchers.IO).launch {
        //get the list of pokemon when they are loaded from repository
        val listOfPokemon =
            PersistenceSingletonRepository.getInstance(applicationContext).getListOfPokemon()
        //download all the image for each pokemon in the list, but only if the image is
        //not present in the directory
        for(pokemon in listOfPokemon) {
            val imageName = "${pokemon.name}.png"
            val file = File("${dir.absolutePath}/$imageName")
            //check if image not exists on internal storage and if is not an official-artwork
            //images that aren't official-artwork has less quality so don't resize
            if(!file.exists()) {
                //download img
                val url = URL(pokemon.linkImage)
                val iS = url.openConnection().getInputStream()
                val opts = BitmapFactory.Options()
                if (!Utils.isBadImage(pokemon.linkImage)) {
                    //request a smaller image
                    opts.inSampleSize = 2
                }
                val bitmap = BitmapFactory.decodeStream(iS, null, opts)
                val fOut= FileOutputStream(file)

                bitmap?.compress(Bitmap.CompressFormat.PNG, 100, fOut)
                fOut.flush()
                fOut.close()
            }

        }
        stopSelf()
    }
    return START_NOT_STICKY
}

【问题讨论】:

  • “需要withContext(Dispatchers.IO) 而不是CoroutineScope(Dispatchers.IO)”——这是什么意思?您需要来自某个地方的CoroutineScope。你打算用什么CoroutineScope
  • URL(pokemon.linkImage) 当我在 CoroutineScope(Dispatchers.IO) 中使用它时收到“不适当的阻塞方法调用”警告。所以我需要使用 withContext(Dispatchers.IO) 而不是 CoroutineScope(Dispatchers.IO)
  • @CommonsWare 打开到 URL 的连接需要一个不是主线程的线程。所以我使用了 CoroutineScope(Dispatchers.IO) 但我收到警告“不适当的阻塞方法调用”

标签: android kotlin kotlin-coroutines android-context


【解决方案1】:

您可以放心地忽略该警告,已知它有很多误报。您在 IO 调度程序中启动了协程,该调度程序是为阻塞调用而设计的。

另一方面,使用没有父级和生命周期绑定的临时CoroutineScope 启动任何东西通常是错误的做法。您应该尊重服务生命周期并在onDestroy 中取消您的协程。参见例如here

【讨论】:

  • 该警告来自 IDE 检查,不是吗?
  • 是的,这不是编译器错误。
猜你喜欢
  • 2019-05-24
  • 2020-06-27
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 2021-06-05
  • 2020-11-18
  • 1970-01-01
相关资源
最近更新 更多