Fragment中使用Coroutine导致导航跳转后新页面UI无法渲染问题
问题诱因排查及修复方案
核心诱因
- ResponseBody的流只能消费一次
ResponseBody的byteStream()是单次可读的流,你在前一个Fragment的协程里已经把整个流读完生成临时文件了,当你跳转到下一个Fragment如果复用同一个pdfResponse实例去加载PDF,流已经处于结束状态,读不到任何数据,自然不会渲染内容,表现为UI空白。 - 协程取消不生效
你用的InputStream.read()是JDK的阻塞IO方法,不响应协程的取消信号,就算前一个Fragment销毁、lifecycleScope触发了取消,这个阻塞读的操作依然会继续执行直到流读完,不会提前终止,也就意味着流还是会被前一个Fragment的协程消费完。 - 异常被全吞排查难度高
你协程的catch块、getTempPdfFile方法的catch块全是空实现,不管是协程取消异常、IO异常还是流读取异常都被你吃掉了,没有日志输出,你根本感知不到运行时的错误。
修复建议
- 避免在跳转前消费ResponseBody
如果下一个Fragment需要加载这个PDF,不要在前一个Fragment提前读流,要么把流消费逻辑放到下一个Fragment执行,要么前一个Fragment读完生成临时文件后,把文件路径传给下一个Fragment直接加载本地文件,不要重复读ResponseBody。 - 让IO操作支持协程取消
可以在每次循环读的时候加ensureActive()判断协程是否已经取消,协程销毁时会直接终止读操作:
while (true) { ensureActive() val read: Int = inputStream.read(fileReader) if (read == -1) { break } outputStream.write(fileReader, 0, read) fileSizeDownloaded += read.toLong() }
- 不要空吞异常
至少在catch块里加日志打印,同时不要捕获协程取消异常,保证协程可以正常终止:
catch (e: Exception) { Log.e("PdfLoad", "加载PDF出错", e) if (e is CancellationException) throw e }
内容的提问来源于stack exchange,提问作者AndroidDev123
相关产品推荐
相关产品推荐

