Kotlin协程中读取Okio source报错流关闭致Bitmap解码失败
问题根因
use 资源关闭块的执行逻辑和协程异步调度逻辑冲突,导致流在解码前被提前关闭:
- Kotlin 的
use扩展函数是同步执行的,代码块内逻辑走完就会立刻自动调用资源的close()方法,不会感知块内启动的异步任务 CoroutineScope.launch是非阻塞调用,启动协程后会立刻返回,不会等待协程内部代码执行完成- 原代码中,
Okio.source(file).use块在启动协程后就立刻执行完毕,自动关闭了底层文件流;等协程被调度到IO线程真正执行BitmapFactory.decodeStream读流时,流资源已经被释放,因此抛出java.io.IOException: Stream Closed,解码返回null。
直接在主线程同步执行时,解码逻辑是在use块内部同步跑完的,流会等解码完成后才关闭,所以能正常生成Bitmap。
修复代码
将Okio资源的生命周期和协程对齐,把use块整体挪到协程内部,保证流在解码完成前不会被提前关闭:
val file = /* ... */ // 建议替换为页面绑定的生命周期协程Scope(如lifecycleScope),避免内存泄漏 CoroutineScope(Dispatchers.IO).launch { Okio.source(file).use { source -> Okio.buffer(source).use { bufferedSource -> val bitmap = BitmapFactory.decodeStream(bufferedSource.inputStream()) withContext(Dispatchers.Main) { view.setImageBitmap(bitmap) } } } }
补充说明
- 无绑定关系的全局
CoroutineScope会导致协程生命周期不受页面管控,页面销毁后协程仍在运行容易触发内存泄漏、View空指针问题,业务场景下优先使用和组件生命周期绑定的协程Scope BitmapFactory.decodeStream读流出错时默认不会抛出上层可捕获的异常,只会返回null,排查解码问题时可通过配置BitmapFactory.Options的debug日志开关获取更详细的底层错误信息
内容的提问来源于stack exchange,提问作者Nicolás Arias
相关产品推荐
相关产品推荐

