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)
}
}
}
}
}
我有几个问题:
- 存储库 class 中
addOnSuccessListener
定义的侦听器的生命周期是多少?
- 在侦听器中调用
callback
函数的范围是什么?
- 当我尝试 运行 这段代码时,
BitmapFactory.decodeStream(it.stream)
将抛出一个 android.os.NetworkOnMainThreadException
,由于调用 decodeStream
函数的上下文,它看起来像是一个异常
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,因此您需要自己安排。有一个库可以帮助转换任务以供协程使用。
假设我有一个存储库 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)
}
}
}
}
}
我有几个问题:
- 存储库 class 中
addOnSuccessListener
定义的侦听器的生命周期是多少? - 在侦听器中调用
callback
函数的范围是什么? - 当我尝试 运行 这段代码时,
BitmapFactory.decodeStream(it.stream)
将抛出一个android.os.NetworkOnMainThreadException
,由于调用decodeStream
函数的上下文,它看起来像是一个异常
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,因此您需要自己安排。有一个库可以帮助转换任务以供协程使用。