Android应用"A resource failed to call close"警告排查与解决咨询
解决pocketsphinx-android中
Assets.syncAssets()引发的资源未关闭警告 问题分析
- 你遇到的
A resource failed to call close警告,通过StrictMode定位到是pocketsphinx-android的Assets.syncAssets()方法未正确关闭可关闭资源导致的。 - 即便按照官方建议在AsyncTask中初始化,或者使用同步版本代码,该警告依然存在;替换为
assets.getExternalDir()后警告消失,是因为这个方法没有触发资源同步操作,也就不存在未关闭的资源问题。
正确的解决方法
方法1:手动修复syncAssets()的资源关闭逻辑
如果需要继续使用syncAssets()(比如需要同步资产文件到外部存储),可以自己封装一个安全版本的同步方法,确保所有打开的流都被正确关闭:
public File safeSyncAssets(Context context) throws IOException { Assets assets = new Assets(context); File externalDir = assets.getExternalDir(); if (externalDir.list().length == 0) { InputStream is = null; OutputStream os = null; try { // 模拟syncAssets的核心同步逻辑,确保每个流都被关闭 String[] assetFiles = assets.list(""); for (String fileName : assetFiles) { is = assets.open(fileName); File outFile = new File(externalDir, fileName); os = new FileOutputStream(outFile); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { os.write(buffer, 0, len); } // 每次循环后关闭当前文件的流 is.close(); os.close(); is = null; os = null; } } finally { // 兜底关闭所有未被关闭的流 if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } assets.close(); // 关闭Assets实例本身 } } return externalDir; }
调用这个方法时,记得在后台线程(比如AsyncTask、Coroutine)中执行,避免阻塞主线程。
方法2:直接使用getExternalDir()替代(若符合需求)
assets.getExternalDir()仅获取已同步的资产目录,如果你的应用首次启动后资产文件已存在,或者不需要从资产目录同步文件到外部存储,可以直接用这个方法替代syncAssets(),这是最简便的方案。- 若首次启动必须同步资产文件到外部存储,建议优先使用方法1的自定义同步逻辑。
方法3:临时忽略StrictMode警告(不推荐)
如果暂时无法修改代码,可以通过StrictMode配置排除该警告,但这只是掩盖问题,无法解决资源泄漏本质:
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy()) .detectLeakedClosableObjects() .penaltyLog() .build());
这种方式不建议长期使用,资源泄漏可能引发内存异常或其他潜在问题。
内容的提问来源于stack exchange,提问作者user1933677
相关产品推荐
相关产品推荐

