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

Firebase addOnSuccessListener callback running context throws `NetworkOnMainThreadException`

假设我有一个存储库 class,它定义了一个从 Firebase 存储中检索图像的方法,并定义了一个调用从视图模型定义的回调的成功侦听器

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)
                    }
                }
            }
        }
    }

我有几个问题:

What's the lifecycle of the listener defined by addOnSuccessListener in the repository class?

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

What's the scope from which the callback function is invoked in the listener?

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

When I try to run this code, BitmapFactory.decodeStream(it.stream) will throw a android.os.NetworkOnMainThreadException that seems like an exception due to the context in which the decodeStream function is invoked

是的,因为回调是在主线程上调用的,而 decodeStream 确实 I/O,如果启用严格模式检测主线程上的 I/O,你会期望它会抛出异常线。这就是为什么 getStream() 的 API 文档说:

Asynchronously downloads the object at this StorageReference via a InputStream. The InputStream should be read on an OnSuccessListener registered to run on a background thread via addOnSuccessListener(Executor, OnSuccessListener)

文档建议您使用执行器安排在主线程以外的线程上调用回调。或者,您可以使用协程,但 API 不支持 Kotlin,因此您需要自己安排。有一个库可以帮助转换任务以供协程使用。

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