8

我在 Android 中收到StrictMode报告的以下违规行为。

02-05 04:07:41.190:错误/严格模式(15093):在附加的堆栈跟踪中获取了资源,但从未释放。有关避免资源泄漏的信息,请参阅 java.io.Closeable。02-05 04:07:41.190:错误/严格模式(15093):java.lang.Throwable:未调用显式终止方法“关闭”

它在抱怨没有正确关闭流。但是,不应该关闭in底层流吗?标记错误的原因可能是什么?

    private ArrayList<Uri> loadPath() {
        ArrayList<Uri> uris = new ArrayList<Uri>();
        if (mFile.exists()) {
            ObjectInputStream in = null;
            try {
                in = new ObjectInputStream(new BufferedInputStream(
                         new FileInputStream(mFile), STREAM_BUFFER_SIZE));
                ArrayList<String> strings = new ArrayList<String>();
                strings.addAll((ArrayList<String>) in.readObject());
                for (String string : strings) {
                    uris.add(Uri.parse(string));
                }
            } catch (Exception e) {
                mFile.delete();
            } finally {
                IOUtils.closeQuietly(in);
            }
        }
        return uris;
     }

    public static void closeQuietly(InputStream input) {
        try {
            if (input != null) {
                input.close();
            }
        } catch (IOException ioe) {
            // ignore
        }
    }
4

4 回答 4

10

查看源代码,两者的构造函数都ObjectInputStream可以BufferedInputStream抛出异常,这将导致FileInputStream在下一行分配对象,但in变量仍将为空:

            in = new ObjectInputStream(
                    new BufferedInputStream(
                            new FileInputStream(mFile), 
                    STREAM_BUFFER_SIZE)
            );

自从in当我们到达块时为空,因此您的方法不会关闭finally该打开的对象,最终导致抱怨:)FileInputStreamcloseQuietly()StrictMode

我建议的最简单的解决方法是将分配分成 3 个变量并调用closeQuietly()每个变量,可能是这样的:

private ArrayList<Uri> loadPath() {
    final ArrayList<Uri> uris = new ArrayList<Uri>();
    if (mFile.exists()) {
        ObjectInputStream ois = null;
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            fis = new FileInputStream(mFile);
            bis = new BufferedInputStream(fis, STREAM_BUFFER_SIZE);
            ois = new ObjectInputStream(bis);
            final ArrayList<String> strings = new ArrayList<String>();
            strings.addAll((ArrayList<String>) ois.readObject());
            for (final String string : strings) {
                uris.add(Uri.parse(string));
            }
        } catch (final Exception e) {
            mFile.delete();
        } finally {
            closeQuietly(fis);
            closeQuietly(bis);
            closeQuietly(ois);
        }
    }
    return uris;
}
于 2012-09-24T21:17:54.623 回答
0
in = new ObjectInputStream(new BufferedInputStream(
                         new FileInputStream(mFile), STREAM_BUFFER_SIZE));

在此代码示例中,您只关闭ObjectInputStream但不关闭BufferedInputStreamFileInputStream,您需要将它们全部关闭。

于 2012-09-27T14:06:05.870 回答
0

如果您查看 ObjectOutpuStream 源代码,您会看到它的 close 方法关闭了底层流。与许多其他代码分析工具一样,Android 的严格模式具有误报,您可以忽略或重写您的代码,这样它就不会抱怨(内联 closeQuietly 方法)。

于 2012-03-01T12:43:32.787 回答
0

该代码应该可以工作,除非您使用的 ProGuard 可能会使字节码有些混乱。

FileInputStreamCloseGuard如果实例已关闭,则具有在 finalize() 中检查的钩子。这就是为什么我认为它应该工作。问题是天气close()是否被调用?

我认为这FileInputStream是创建的(因为 StrictMode 引发了异常),但最终引发了一个异常并在某处被忽略。

    try {
        if (input != null) {
            input.close();
        }
    } catch (Exception ioe) {
        // check exception here
    }
于 2012-09-24T13:08:48.537 回答