1. 程式人生 > >Android 使用MediaRecorder錄音呼叫stop()方法的時候報錯

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啊