假设我有一个存储库类,该类定义了一种从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
函数的上下文,这似乎是一个异常存储库类中的addOnSuccessListener定义的侦听器的生命周期是什么?
您在这里使用它的方式,它没有生命周期。回调将无限期持续。
在侦听器中从哪个范围调用回调函数?
它没有协程范围。只要准备好结果,回调就会在主线程上调用。
[当我尝试运行此代码时,BitmapFactory.decodeStream(it.stream)
将引发android.os.NetworkOnMainThreadException,由于调用了stream的上下文,这似乎是一个异常
是的,由于回调是在主线程上调用的,并且解码流会执行I / O,因此,如果启用了严格模式以检测主线程上的I / O,您将期望它引发异常。这就是为什么getStream()的API文档说:
通过InputStream在此StorageReference异步下载对象。文档建议您安排使用Executor在除主线程之外的其他线程上调用回调。另外,您可以使用协程,但是API不支持Kotlin,因此您需要自己进行安排。有一个库可以帮助转换任务以使用协程。InputStream应该在通过addOnSuccessListener(Executor,OnSuccessListener)注册为在后台线程上运行的OnSuccessListener上读取