StrictMode complains about InputStream not being closed

Roopesh Kohad picture Roopesh Kohad · Mar 1, 2012 · Viewed 7.4k times · Source

I'm getting the following violation reported by StrictMode in Android.

02-05 04:07:41.190: ERROR/StrictMode(15093): A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. 02-05 04:07:41.190: ERROR/StrictMode(15093): java.lang.Throwable: Explicit termination method 'close' not called

It is cribbing about not closing streams properly. However, shouldn't closing in close the underlying streams? What could be the reason for the flagged error?

    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
        }
    }

Answer

Joe picture Joe · Sep 24, 2012

Looking at the source code, the constructors for both ObjectInputStream and BufferedInputStream can throw exceptions which would cause a FileInputStream object to be allocated on the following line, but the in variable will still be null:

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

Since in is null when we get to the finally block, that open FileInputStream object will not be closed by your closeQuietly() method, causing StrictMode to complain eventually :)

The simplest fix I would suggest is to split that allocation into 3 variables and call closeQuietly() on each, maybe something like this:

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;
}