Android 使用MediaRecorder錄音呼叫stop()方法的時候報錯
這個問題在網上看到了太多的答案,一直提示說按照官網的api的順序來,其實解決問題的方法不是這樣的,那樣沒法解決問題,照著那個順序來也米有用
我們得知道為什麼它停止不了,為什麼停止閃退了,
這裡面有個結論就是:閃退必然是出現了控制值的錯誤,在Java中就是java.lang.NullXXException的錯誤
好像沒有其他的原因導致閃退把,
stop 就刪除,是因為stop的物件不存在,這個懂把,
stop物件不存在,說明物件new失敗,這個懂吧,
stop的物件new失敗,那就需要看new執行了哪些操作了:
<strong><span style="font-size:18px;">mr=new MediaRecorder(); mr.setAudioSource(MediaRecorder.AudioSource.MIC); mr.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mr.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); mr.setMaxDuration(10000); mr.setOutputFile(Environment.getExternalStorageDirectory().getPath()+File.separator+"fisii77s.3gp"); mr.prepare(); mr.start();</span></strong>
我相信大家都是這樣的做法,關鍵是我們前面包了一層if(mr==null)的判斷了
我在程式碼中報錯之前是這樣寫的:
也就是說如果物件存在,沒有被銷燬掉,我就不用建立了,按照常理說,確實應該這樣判斷對吧,可是常理一般都是錯誤的,<strong><span style="font-size:18px;"> public void start(Context context, String name) { if (!Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED)) { return; } if (mRecorder == null) { mRecorder = new MediaRecorder(); mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); mRecorder.setOutputFile(UtilsForChat.getMusicFilePath(context, name)); try { mRecorder.prepare(); mRecorder.start(); mEMA = 0.0; } catch (IllegalStateException e) { System.out.print(e.getMessage()); } catch (IOException e) { System.out.print(e.getMessage()); } } }</span></strong>
在java中 判斷 一個物件是否為空確實是 == null 關鍵是 ==null是有誰來判斷的 這個好像是說面試的時候經常這樣考 我這裡還是講講我一直那麼理解的東西啊,本人還在讀書,希望對以後找工作面試的時候有用 哈哈
== 這個判斷是地址值比較的,equals是內容值比較的
== 這個地址值是指堆記憶體的,equals這個值是指在棧記憶體中的
在我們知道null判斷的機制的了之後,我們就要去考慮,如果這個物件還存在,我們是否能直接用這個物件呢,經過測試答案是不行的,
接下來再接著說,如果我們第一次建立一個MediaRecorder物件,當我們錄音結束之後肯定是停止並且釋放了的,否則錄音檔案就不成功了,
停止,停止的是jni物件,釋放,釋放的jni裡面的物件,同時也釋放了java物件裡面的棧記憶體的值,堆記憶體還保留著呢,引用為空 這裡搞明白了,原因也就出來了,
關於這裡面jni機制如果不懂,可以看我上篇文章,講解的很詳細
釋放之後,如果馬上執行第二次錄音,這個時候上面的if程式碼就需要判斷了,很明顯if裡面的語句是不會被執行的,因為堆記憶體沒有被釋放掉啊,但是jni裡面的物件全部被釋放掉了
這個時候如果你還用這個物件去錄音,那麼結果就是你對著空氣說話,錄的音也成了空氣,然後你鬆開手指也就是錄音物件停止的時候,無法停止了,因為jni物件是空的,不存在,怎麼去停止呢,程式直接閃退,原因就是這樣的了
解決辦法就是這個時候如果你的物件不為空,你需要再重新建立一次,主要是保證你錄音不會成為空氣,
<strong><span style="font-size:18px;"> public void start(Context context, String name) {
if (!Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED)) {
return;
}
if (mRecorder == null) {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile(UtilsForChat.getMusicFilePath(context, name));
try {
mRecorder.prepare();
mRecorder.start();
mEMA = 0.0;
} catch (IllegalStateException e) {
System.out.print(e.getMessage());
} catch (IOException e) {
System.out.print(e.getMessage());
}
}else{
stop();
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile(UtilsForChat.getMusicFilePath(context, name));
try {
mRecorder.prepare();
} catch (IllegalStateException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mRecorder.start();
}
}</span></strong>
程式碼就變成這樣了,其實,這裡面更簡單點就是每次不判斷,進來直接把原來的停止,然後再建立 可以省掉很多程式碼了
然後就是stop函式,一定要寫對,否則還是報錯的哦:
<strong><span style="font-size:18px;"> public void stop() {
if (mRecorder != null) {
try {
mRecorder.stop();
} catch (IllegalStateException e) {
// TODO 如果當前java狀態和jni裡面的狀態不一致,
//e.printStackTrace();
mRecorder = null;
mRecorder = new MediaRecorder();
}
mRecorder.release();
mRecorder = null;
}
}</span></strong>
這裡面有人肯定問,你這裡面stop已經搞了異常丟擲,為什麼上面的建立還加上else那樣的程式碼呢,
這裡面也是機型的原因然後導致我最終還是保留了這段程式碼 因為要保證你說的話,錄音的音不會成為空氣啊 這也是很重要的bug啊