2012-03-01 119 views
8

我在Android中收到StrictMode報告的以下違規行爲。StrictMode抱怨InputStream未關閉

4月2日至5日:07:41.190:ERROR/StrictMode(15093):資源在連接的堆棧跟蹤獲取 但從未發佈。有關避免資源泄漏的信息,請參見java.io.Closeable。 4月2日至五日:07:41.190: ERROR/StrictMode(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 
     } 
    } 
+0

不知道StrictMode檢查器有多聰明,但它看起來像被***延遲關閉***弄糊塗了,即使用一個實用程序爲您關閉流。 – Perception 2012-03-01 12:08:51

+0

在我的情況下,即使在'finally'子句中內聯'close()',我也會得到這個錯誤。 – 2012-09-24 13:26:42

回答

0

如果你看看ObjectOutpuStream源代碼,你會看到它的close方法關閉底層流。像許多其他代碼分析工具一樣,Android的嚴格模式有誤報,您可以忽略或重寫代碼,以免發生抱怨(內聯closeQuietly方法)。

+0

Android的StrictMode不是代碼分析工具。它在源代碼中用'finalize()'看着'FileInputStream'和'CloseGuard'。 – pawelzieba 2012-09-24 13:06:54

0

該代碼應該可以工作,除非您使用的ProGuard可能會與字節碼混淆。

FileInputStream掛鉤到CloseGuard如果實例已關閉,則在finalize()中檢查它。這就是爲什麼我認爲它應該起作用。問題是天氣close()被調用或不?

我認爲FileInputStream被創建(因爲StrictMode拋出的異常),但最後拋出異常並在某處被忽略。

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

查看源代碼,對於ObjectInputStreamBufferedInputStream構造函數可以拋出異常,這將導致FileInputStream對象以下行來分配,但in變量仍然爲空:

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

由於in爲空時,我們得到的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; 
} 
+0

斑點,但在我的情況下,沒有發生異常。(我會回去仔細檢查一下。) – 2012-09-25 12:23:19

+0

也許我在這裏錯了,但StrictMode沒有抱怨「可能出現的情況」呢?它會抱怨例如來自主線程的IO訪問,即使沒有實際引起ANR。 – dbm 2012-09-26 12:55:37

+2

它應該抱怨實際發生的事情。在主線程上訪問IO的情況下,主線程上確實會發生IO訪問。 (這不僅僅是理論上的)。所以,如果它真的泄露了,它應該只會抱怨InputStream泄漏。 – 2012-09-27 12:03:27

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

在此代碼示例,你只關閉ObjectInputStream但不BufferedInputStreamFileInputStream,您需要關閉它們全部。

+0

你呢?這與Konstantin Solomatov的答案相矛盾。 – 2012-09-27 14:11:15

+0

@GrahamBorland只需對它進行測試即可看到。 – 2012-09-27 14:14:36