我一直在尝试测量麦克风在我的设备后台操作时使用的电量,所以我写了一个小应用程序来测试它。
在我的手机外置存储器上,我有一个用该应用程序创建的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)`
我没有用android做过很多文件IO的东西,所以我不确定我在这里做错了什么。 如果有人不介意指出我哪里出错了,我将非常感激。
该课程的代码如下。
提前致谢 科里:)
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 :(得分:0)
在尝试对其执行任何操作之前,您似乎正在将整个音频文件加载到内存中。这是一个糟糕的方法,因为你的文件看起来像672164876字节(641MB),而且我猜这是方式比你允许在移动设备上分配的RAM多,最多可能是1在所有正在运行的应用程序(以及Android操作系统本身)之间共有2GB的RAM。
虽然您尝试在如此低的级别(读取所有字节并将其直接写入将播放它们的内容)这样做很棒,但我建议您查看内置的Android媒体API,例如MediaPlayer
解释in this other StackOverflow post或更高级别的库,其中任何一个都应该处理将文件流式传输到内存中并将其播放的所有细节,以便您不必这样做。