调用getContentResolver().openFileDescriptor()触发LeakedClosableViolation泄漏
问题原因
本次泄漏的根源是你只关闭了从ParcelFileDescriptor派生的FileInputStream,但ParcelFileDescriptor本身是独立的可关闭资源,它内部持有原生层的文件描述符,不会因为派生的输入流关闭就自动释放自身资源。从StrictMode的告警堆栈也可以明确看到,泄漏触发点是ParcelFileDescriptor的终结方法检测到close方法从未被主动调用,所以触发了资源泄漏告警。
解决方案
方案1:推荐使用try-with-resources自动关闭资源(适配Android 4.4/API 19及以上版本,覆盖当前绝大多数活跃设备)
try-with-resources语法会自动按声明逆序关闭所有实现了Closeable接口的资源,无需手动编写finally关闭逻辑:
try (ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(this.documentFile.getUri(), "r"); FileInputStream is = new FileInputStream(pfd.getFileDescriptor())) { // 原有业务逻辑 ... } catch (IOException e) { // 异常处理逻辑 }
方案2:兼容低版本的传统finally写法
如果需要支持API 19以下的设备,在原有finally逻辑中补充ParcelFileDescriptor的关闭逻辑即可:
ParcelFileDescriptor pfd = null; FileInputStream is = null; try { pfd = context.getContentResolver().openFileDescriptor(this.documentFile.getUri(), "r"); is = new FileInputStream(pfd.getFileDescriptor()); // 原有业务逻辑 ... } finally { IOUtils.closeQuietly(is); IOUtils.closeQuietly(pfd); // 新增ParcelFileDescriptor的关闭逻辑 }
注意:IOUtils.closeQuietly会自动处理空指针和关闭时的异常,无需额外加判空逻辑
内容的提问来源于stack exchange,提问作者user1026605
相关产品推荐
相关产品推荐

