Контекст запуска обратного вызова addOnSuccessListener Firebase выдает исключение NetworkOnMainThreadException. - PullRequest
0 голосов
/ 29 мая 2020

Предположим, у меня есть класс репозитория, который определяет метод для получения изображения из Firebase Storage и определяет успешный прослушиватель, который вызывает обратный вызов, определенный из модели представления.

fun getAdImg(imgId: String, callback: (stream: Bitmap?) -> Unit) {
        storage.child(FOLDER).child(imgId+EXTENSION).stream
            .addOnSuccessListener {
                callback(BitmapFactory.decodeStream(it.stream))
                Log.i(TAG, "getAdImg success")
            }
            .addOnCanceledListener {
                Log.e(TAG, "getAdImg canceled")
            }
            .addOnFailureListener {
                Log.e(TAG, "getAdImg failure")
            }

    }

Функция в модели представления, которая определяет обратный вызов и вызывает репозиторий:

fun loadImage(imgId: String?) {
        imgId?.let { id ->
            if (_img.value == null) {
                viewModelScope.launch (context = IO) {
                    AdvertisementRepository.getInstance().getAdImg(id) { bitmap ->
                        _img.postValue(bitmap)
                    }
                }
            }
        }
    }

У меня есть пара вопросов:

  • Какой жизненный цикл слушателя определяется addOnSuccessListener в классе репозитория ?
  • Из какой области действия вызывается функция callback в слушателе?
  • Когда я пытаюсь запустить этот код, BitmapFactory.decodeStream(it.stream) выдаст android.os.NetworkOnMainThreadException, который выглядит как исключение из-за контекста, в котором вызывается функция decodeStream

1 Ответ

1 голос
/ 31 мая 2020

Какой жизненный цикл слушателя определяется addOnSuccessListener в классе репозитория?

То, как вы его используете здесь, у него нет жизненного цикла. Обратный вызов будет сохраняться бесконечно.

Из какой области действия вызывается функция обратного вызова в слушателе?

У нее нет области сопрограммы. Обратный вызов будет вызываться в основном потоке всякий раз, когда будет готов результат.

Когда я попытаюсь запустить этот код, BitmapFactory.decodeStream(it.stream) вызовет исключение android .os.NetworkOnMainThreadException, которое выглядит как исключение из-за контекста, в котором вызывается функция decodeStream

Да, поскольку обратный вызов вызывается в основном потоке, а decodeStream выполняет ввод-вывод, вы ожидаете, что он выдаст исключение, если строго режим включен для обнаружения ввода-вывода в основном потоке. Вот почему в документации API для getStream () сказано:

Асинхронно загружает объект в этот StorageReference через InputStream. InputStream должен быть прочитан на OnSuccessListener, зарегистрированном для запуска в фоновом потоке через addOnSuccessListener (Executor, OnSuccessListener)

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

https://github.com/Kotlin/kotlinx.coroutines/tree/master/integration/kotlinx-coroutines-play-services

...