Firebase addOnSuccessListener回调运行上下文会抛出`NetworkOnMainThreadException`

问题描述 投票:0回答:1

假设我有一个存储库类,该类定义了一种从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函数的上下文,这似乎是一个异常
android multithreading kotlin firebase-storage coroutine
1个回答
0
投票
存储库类中的addOnSuccessListener定义的侦听器的生命周期是什么?

您在这里使用它的方式,它没有生命周期。回调将无限期持续。

在侦听器中从哪个范围调用回调函数?

它没有协程范围。只要准备好结果,回调就会在主线程上调用。

[当我尝试运行此代码时,BitmapFactory.decodeStream(it.stream)将引发android.os.NetworkOnMainThreadException,由于调用了stream的上下文,这似乎是一个异常

是的,由于回调是在主线程上调用的,并且解码流会执行I / O,因此,如果启用了严格模式以检测主线程上的I / O,您将期望它引发异常。这就是为什么getStream()的API文档说:

通过InputStream在此StorageReference异步下载对象。

InputStream应该在通过addOnSuccessListener(Executor,OnSuccessListener)注册为在后台线程上运行的OnSuccessListener上读取

文档建议您安排使用Executor在除主线程之外的其他线程上调用回调。另外,您可以使用协程,但是API不支持Kotlin,因此您需要自己进行安排。有一个库可以帮助转换任务以使用协程。

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

© www.soinside.com 2019 - 2024. All rights reserved.