You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 10:45:58