2014-11-03 40 views
3

我一直在嘗試測量麥克風在我的設備上的背景中操作時使用的電池電量,所以我寫了一個小應用程序來測試它。App force closing - OutOfMemoryError

在我的手機外部存儲,我有一個600MB的PCM文件錄製應用程序創建,以及第二個100MB一個。

當我運行應用程序並嘗試播放100mb文件時,它工作正常。 但是當我嘗試和發揮更大的600MB之一,它崩潰的代碼行:

InputStream is = new FileInputStream(file); 

而且logcat中給出了錯誤:

`11-03 16:31:03.654 16916-16916/com.bacon.corey.audiotimeshift I/art﹕ Alloc sticky concurrent mark sweep GC freed 6307(421KB) AllocSpace objects, 1(12KB) LOS objects, 33% free, 15MB/23MB, paused 678us total 14.444ms 
11-03 16:31:03.663 16916-16916/com.bacon.corey.audiotimeshift I/art﹕ Alloc partial concurrent mark sweep GC freed 213(22KB) AllocSpace objects, 0(0B) LOS objects, 40% free, 15MB/26MB, paused 659us total 7.132ms 
11-03 16:31:03.679 16916-16916/com.bacon.corey.audiotimeshift I/art﹕ Alloc concurrent mark sweep GC freed 15(12KB) AllocSpace objects, 0(0B) LOS objects, 40% free, 15MB/26MB, paused 830us total 14.191ms 
11-03 16:31:03.681 16916-16916/com.bacon.corey.audiotimeshift I/art﹕ Forcing collection of SoftReferences for 641MB allocation 
11-03 16:31:03.695 16916-16916/com.bacon.corey.audiotimeshift I/art﹕ Alloc concurrent mark sweep GC freed 11(344B) AllocSpace objects, 0(0B) LOS objects, 39% free, 15MB/26MB, paused 645us total 13.989ms 
11-03 16:31:03.700 16916-16916/com.bacon.corey.audiotimeshift E/art﹕ Throwing OutOfMemoryError "Failed to allocate a 672164876 byte allocation with 11094652 free bytes and 176MB until OOM" 
11-03 16:31:03.703 16916-16916/com.bacon.corey.audiotimeshift D/AndroidRuntime﹕ Shutting down VM 
11-03 16:31:03.713 16916-16916/com.bacon.corey.audiotimeshift E/AndroidRuntime﹕ FATAL EXCEPTION: main 
    Process: com.bacon.corey.audiotimeshift, PID: 16916 
    java.lang.IllegalStateException: Could not execute method of the activity 
      at android.view.View$1.onClick(View.java:4007) 
      at android.view.View.performClick(View.java:4756) 
      at android.view.View$PerformClick.run(View.java:19749) 
      at android.os.Handler.handleCallback(Handler.java:739) 
      at android.os.Handler.dispatchMessage(Handler.java:95) 
      at android.os.Looper.loop(Looper.java:135) 
      at android.app.ActivityThread.main(ActivityThread.java:5221) 
      at java.lang.reflect.Method.invoke(Native Method) 
      at java.lang.reflect.Method.invoke(Method.java:372) 
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694) 
    Caused by: java.lang.reflect.InvocationTargetException 
      at java.lang.reflect.Method.invoke(Native Method) 
      at java.lang.reflect.Method.invoke(Method.java:372) 
      at android.view.View$1.onClick(View.java:4002) 
            at android.view.View.performClick(View.java:4756) 
            at android.view.View$PerformClick.run(View.java:19749) 
            at android.os.Handler.handleCallback(Handler.java:739) 
            at android.os.Handler.dispatchMessage(Handler.java:95) 
            at android.os.Looper.loop(Looper.java:135) 
            at android.app.ActivityThread.main(ActivityThread.java:5221) 
            at java.lang.reflect.Method.invoke(Native Method) 
            at java.lang.reflect.Method.invoke(Method.java:372) 
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694) 
    Caused by: java.lang.OutOfMemoryError: Failed to allocate a 672164876 byte allocation with 11094652 free bytes and 176MB until OOM 
      at com.bacon.corey.audiotimeshift.MainActivity.play(MainActivity.java:87) 
            at java.lang.reflect.Method.invoke(Native Method) 
            at java.lang.reflect.Method.invoke(Method.java:372) 
            at android.view.View$1.onClick(View.java:4002) 
            at android.view.View.performClick(View.java:4756) 
            at android.view.View$PerformClick.run(View.java:19749) 
            at android.os.Handler.handleCallback(Handler.java:739) 
            at android.os.Handler.dispatchMessage(Handler.java:95) 
            at android.os.Looper.loop(Looper.java:135) 
            at android.app.ActivityThread.main(ActivityThread.java:5221) 
            at java.lang.reflect.Method.invoke(Native Method) 
            at java.lang.reflect.Method.invoke(Method.java:372) 
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)` 

我沒有做太多的文件IO的東西與Android ,所以我不確定我在這裏做錯了什麼。 如果有人不介意指出我出錯的地方,我會非常感激。

該類的代碼如下。

在此先感謝 科瑞:)

 public void play(View view) { 
     Toast.makeText(this, "play", Toast.LENGTH_SHORT).show(); 

// Get the file we want to playback. 
     File file = new File(Environment.getExternalStorageDirectory() + File.separator + "ACS.pcm"); 
// Get the length of the audio stored in the file (16 bit so 2 bytes per short) 
// and create a short array to store the recorded audio. 
     int musicLength = (int)(file.length()/2); 
     short[] music = new short[musicLength]; 


     try { 
// Create a DataInputStream to read the audio data back from the saved file. 
      InputStream is = new FileInputStream(file); 
      BufferedInputStream bis = new BufferedInputStream(is); 
      DataInputStream dis = new DataInputStream(bis); 

// Read the file into the music array. 
      int i = 0; 
      while (dis.available() > 0) { 
       music[musicLength-1-i] = dis.readShort(); 
       i++; 
      } 


// Close the input streams. 
      dis.close(); 


// Create a new AudioTrack object using the same parameters as the AudioRecord 
// object used to create the file. 
      AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 
        44100, 
        AudioFormat.CHANNEL_OUT_MONO, 
        AudioFormat.ENCODING_PCM_16BIT, 
        musicLength, 
        AudioTrack.MODE_STREAM); 
// Start playback 
      audioTrack.play(); 

// Write the music buffer to the AudioTrack object 
      audioTrack.write(music, 0, musicLength); 


     } catch (Throwable t) { 
      Log.e("AudioTrack","Playback Failed"); 
     } 
    } 

回答

0

它看起來像你加載整個音頻文件到內存中試圖用它做任何事情之前。這是一個糟糕的做法,因爲你的文件看起來像是672164876字節(641MB),我猜這是的方式更多的內存比你可以在移動設備上分配的內存可能至多有1-2GB在所有正在運行的應用程序(以及Android操作系統本身)之間共享。

雖然這是一種非常棒的方式,但您試圖在如此低的級別上執行此操作(讀取所有字節並將它們直接寫入可以播放它們的內容),我建議您查看內置的Android媒體API如MediaPlayer解釋in this other StackOverflow post或某些更高級別的庫,其中任何應該處理所有的細節,將文件流式傳輸到內存中並播放它,因此您不必這樣做。