Неуместный вызов метода блокировки, но функция приостановки «withContext» должна вызываться только из сопрограммы или другой функции приостановки

#android #kotlin #kotlin-coroutines #android-context

Вопрос:

В моей службе мне нужно обратиться к onStartCommand некоторым методам, которые требуют withContext(Dispatchers.IO) вместо CoroutineScope(Dispatchers.IO) этого, например:

  • url = URL(покемон.Изображение ссылки)
  • url.openConnection().getInputStream()
  • fOut= Поток вывода файла(файл)
  • Фут.смыть()
  • fOut.закрыть()

Но Suspend function 'withContext' should be called only from a coroutine or another suspend function . Так что если onStartCommand не может быть функцией приостановки, потому что она переопределена и withContext не может быть вызвана сопрограммой из-за Inappropriate blocking method call методов

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

Как я могу решить эту проблему?

Моя команда OnStart ():

 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
}
 

Комментарии:

1. «это требует withContext(Dispatchers.IO) взамен CoroutineScope(Dispatchers.IO) » — что это значит? Тебе нужно CoroutineScope откуда-то. Что CoroutineScope вы собираетесь использовать?

2. URL(pokemon. linkImage) получаю предупреждение «Неуместный вызов метода блокировки», когда я использую его в сопрограмме(Dispatchers.IO). Поэтому мне нужно использовать withContext(Диспетчеры. IO) вместо сопрограммы(Dispatchers.IO)

3. @CommonsWare Для открытого подключения к URL-адресу требуется поток, который не является основным потоком. Поэтому я использовал сопрограмму(Диспетчеры. IO) , но я получаю предупреждение «Неуместный вызов метода блокировки»

Ответ №1:

Вы можете смело игнорировать это предупреждение, известно, что оно имеет много ложных срабатываний. Вы запустили сопрограмму в диспетчере ввода-вывода, которая предназначена для блокировки вызовов.

С другой стороны, запуск чего-либо с помощью специального CoroutineScope приложения, у которого нет родителя и привязки к жизненному циклу, обычно является неправильным. Вы должны уважать жизненный цикл службы и отменить свою сопрограмму onDestroy . Смотрите, например, здесь.

Комментарии:

1. Это предупреждение исходит от проверок IDE, не так ли?

2. Да, это не ошибка компилятора.