每次测试我的应用程序时,我都会在 logcat 中收到此警告..
W A resource failed to call close.
我在
onCreate()
方法中使用了我在网上找到的以下代码来抛出异常和堆栈跟踪以找出导致它的原因..
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy()).detectLeakedClosableObjects().build());
这产生了以下堆栈跟踪..
StrictMode policy violation: android.os.strictmode.LeakedClosableViolation: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
at android.os.StrictMode$AndroidCloseGuardReporter.report(StrictMode.java:1994)
at dalvik.system.CloseGuard.warnIfOpen(CloseGuard.java:336)
at java.io.FileInputStream.finalize(FileInputStream.java:508)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:339)
at java.lang.Daemons$FinalizerDaemon.processReference(Daemons.java:324)
at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:300)
at java.lang.Daemons$Daemon.run(Daemons.java:145)
at java.lang.Thread.run(Thread.java:1012)
Caused by: java.lang.Throwable: Explicit termination method 'close' not called
at dalvik.system.CloseGuard.openWithCallSite(CloseGuard.java:288)
at dalvik.system.CloseGuard.open(CloseGuard.java:257)
at java.io.FileInputStream.<init>(FileInputStream.java:176)
at edu.cmu.pocketsphinx.Assets.getExternalItems(Assets.java:149)
at edu.cmu.pocketsphinx.Assets.syncAssets(Assets.java:253)
at com.example.atest.MainActivity$SetupTask.doInBackground(MainActivity.java:127)
at com.example.atest.MainActivity$SetupTask.doInBackground(MainActivity.java:118)
at android.os.AsyncTask$3.call(AsyncTask.java:394)
at java.util.concurrent.FutureTask.run(FutureTask.java:264)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at java.lang.Thread.run(Thread.java:1012)
我已经追溯到这段代码..
private static class SetupTask extends AsyncTask<Void, Void, Exception> {
WeakReference<MainActivity> activityReference;
SetupTask(MainActivity activity) {
this.activityReference = new WeakReference<>(activity);
}
@Override
protected Exception doInBackground(Void... params) {
try {
Assets assets = new Assets(activityReference.get());
File assetDir = assets.syncAssets();
activityReference.get().setupRecognizer(assetDir);
} catch (IOException e) {
return e;
}
return null;
}
@Override
protected void onPostExecute(Exception result) {
if (result != null) {
((TextView) activityReference.get().findViewById(R.id.status_text)).setText(R.string.status_fail);
Log.d(TAG, "SetupTask: Exception: " + result.getMessage());
// TODO: decide what to do when there is an exception
} else {
Log.d(TAG, "SetupTask: startSearch()");
activityReference.get().startSearch();
}
}
}
这是我从 pocketsphinx-android 获得的代码。设置资产和语音识别器需要时间,因此他们建议在异步任务中执行此操作,以防止主线程上丢帧。我可以采取一些明显的措施来消除此警告吗?我在下面测试了此代码的同步版本,并生成相同的堆栈跟踪。
try {
Assets assets = new Assets(this);
File assetDir = assets.syncAssets();
setupRecognizer(assetDir);
startSearch();
} catch (IOException e) {
Log.d(TAG, e.getMessage());
}
我已将其进一步固定为 ..
File assetDir = assets.syncAssets();
因为我把它改成了..
File assetDir = assets.getExternalDir()
我没有收到任何警告。看起来像是 pocketsphinx-android 问题。
OP 已经回答了他自己的问题,我的答案是展示为什么
syncAssets()
会导致 logcat 警告,而 getExternalDir()
不会。
根据 PocketSphinx 源,
syncAssets()
调用两个内部方法,getItems()
和 getExternalItems()
,这两个方法都打开 InputStream
(后者打开 FileInputStream
)。
例如在 getItems()
:
Reader reader = new InputStreamReader(openAsset(path + HASH_EXT));
openAsset()
:
private InputStream openAsset(String asset) throws IOException {
return assetManager.open(new File(SYNC_DIR, asset).getPath());
}
您会因为内联
InputStreams
未关闭而收到警告。