StrictMode жалуется, что InputStream не закрывается

Я получаю следующее нарушение, о котором сообщает StrictMode в Android.

02-05 04: 07: 41.190: ERROR/StrictMode (15093): был приобретен ресурс при подключенной трассировке стека, но никогда не выпускается. См. Java.io.Closeable для информацию об избежании утечки ресурсов. 02-05 04: 07: 41.190: ERROR/StrictMode (15093): java.lang.Throwable: Явное завершение метод 'close' не называется

Это кривая о том, чтобы не закрывать потоки должным образом. Однако не следует закрывать 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
 }
 }
</string></string></string></uri></uri></uri>
4 ответа

Глядя на исходный код, конструкторы для ObjectInputStream и BufferedInputStream может генерировать исключения, которые вызывают выделение объекта FileInputStream в следующей строке, но переменная in по-прежнему будет иметь значение null:

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

Так как in имеет значение null, когда мы попадаем в блок finally, открытый объект FileInputStream не будет закрыт вашим методом closeQuietly(), в результате чего 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;
}
</string></string></string></uri></uri></uri>


Если вы посмотрите на источник ObjectOutpuStream, вы увидите, что его метод close закрывает базовый поток. Строгий режим Android, как и многие другие инструменты анализа кода, имеет ложные срабатывания, которые вы можете игнорировать или переписывать свой код, чтобы он не стал жаловаться (встроенный метод closeQuietly).


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

В этом примере кода вы закрываете только ObjectInputStream, но не BufferedInputStream или FileInputStream, вам нужно закрыть их все.


Код должен работать, если вы не используете ProGuard, который может немного испортить байт-код.

FileInputStream имеет привязки к CloseGuard, который проверяется в finalize(), если экземпляр был закрыт. Вот почему я думаю, что это должно сработать. Вопрос: была ли вызвана погода close() или нет?

Я думаю, что FileInputStream был создан (поскольку исключение StrictMode выбрано), но затем исключение было окончательно отброшено и где-то проигнорировано.

try {
 if (input != null) {
 input.close();
 }
 } catch (Exception ioe) {
 // check exception here
 }

licensed under cc by-sa 3.0 with attribution.