android - Firebase addOnSuccessListener 回调运行上下文抛出`NetworkOnMainThreadException`
问题描述
假设我有一个存储库类,它定义了一个从 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)
}
}
}
}
}
我有一些问题:
addOnSuccessListener
存储库类中定义的侦听器的生命周期是什么?callback
在侦听器中调用函数的范围是什么?- 当我尝试运行此代码时,由于调用函数的上下文,
BitmapFactory.decodeStream(it.stream)
将抛出一个android.os.NetworkOnMainThreadException
看起来像异常的异常decodeStream
解决方案
存储库类中 addOnSuccessListener 定义的监听器的生命周期是什么?
你在这里使用它的方式,它没有生命周期。回调将无限期持续。
在侦听器中调用回调函数的范围是什么?
它没有协程范围。只要结果准备好,就会在主线程上调用回调。
当我尝试运行此代码时,
BitmapFactory.decodeStream(it.stream)
将抛出一个 android.os.NetworkOnMainThreadException,由于调用 decodeStream 函数的上下文,这似乎是一个异常
是的,由于回调是在主线程上调用的,并且 decodeStream 执行 I/O,如果启用严格模式来检测主线程上的 I/O,您会期望它会抛出异常。这就是为什么 getStream() 的 API 文档说:
通过 InputStream 异步下载此 StorageReference 处的对象。应该在通过 addOnSuccessListener(Executor, OnSuccessListener) 注册以在后台线程上运行的 OnSuccessListener 上读取 InputStream
文档建议您安排在使用 Executor 的主线程以外的线程上调用回调。或者,您可以使用协程,但 API 不支持 Kotlin,因此您需要自行安排。有一个库可以帮助将任务转换为协程使用。
推荐阅读
- jquery - URL 中的问号未正确编码
- php - 函数 get_post 并返回 mysqli_real_escape_string - PHP
- git - Github.io 找不到工件:
- wordpress - 如何通过 IP 地址限制对 WordPress 管理员登录页面的访问,而不影响客户注销过程?
- java - 如何在 Spring Security antmatchers 中使用参数
- sql - 在 PostgreSQL 中为特定 ID 选择最大值
- django - 使用来自不同模型模板的 kwargs 在 Django 中创建 CreateView
- java - 如果出现任何类型的异常,重定向到错误控制器?
- vue.js - VueJS 2:如何按顺序加载静态 JS?
- highcharts - 在 jhipster 中使用 highcharts