Android MediaPlayer 播放器網路音訊播放總結
阿新 • • 發佈:2019-01-04
在近期的Android 系統MediapPalyer使用中,碰到了不少問題。其中一些問題也是在特殊的條件下才會出現,嘗試很多方法才解決。這裡做了總結,也跟大家分享一下:
1.播放器需要多執行緒實現
一般我們會把MediaPlayer放到Service中,做播放相關的邏輯操作。但是因為Service也是在主執行緒中,如果播放器內部發生阻塞就會導致整個UI執行緒阻塞。尤其播放網路資源的時候,播放器的prepare()方法會快取足夠的資源才會播放。這裡建議新建一個播放執行緒控制MediaPlayer的播放。這裡我是通過android.os.HandlerThread和Handler實現控制子執行緒播放操作。
2.網路問題較差時,mediaPlayer.prepare()阻塞執行緒問題的解決
樓主開始呼叫播放程式碼如下。經過測試當網速不好的情況下(10kB)一下。播放執行緒會卡在
mediaPlayer.prepare()的內部方法中。期間使用了幾個方法:
1.將mediaPlayer.prepare()換成mediaPlayer.prepareAsync()使用非同步準備的方式。經過測試用非同步的方式,當頻繁切換的時候介面會出現ANR。原因應該是多執行緒控制的問題。經過查資料需要在mediaPlayer.reset()之前呼叫stop的方法。這樣做的確介面不ANR,但是因為呼叫的狀態不合法會出現IllegalStateException異常。並且這樣也會讓播放器內部出現問題。在呼叫mediaPlayer.setDataSource(path)的時候返回各種不同的錯誤。
2.因為第一種方案問題更多,之後我還是繼續使用mediaPlayer.prepare()方法。想通過執行緒的中斷來解決問題。因為是阻塞在MediapPalyer的內部只能通過兩種方案,一種就是讓MediapPalyer內部報異常,一種就是強制結束執行緒。這裡嘗試第一種方案的時候發現。當播放執行緒阻塞的時候mediaPlayer.prepare(),在主執行緒呼叫mediaPlayer.stop()方法可以讓prepare方法報IllegalStateException(經過測試這個是必現的,API中有stop方法呼叫合法狀態)。解決方案具體如下:當播放新歌曲的時候,如果發現播放執行緒阻塞了,也就是當前的狀態是preparing狀態,主執行緒中呼叫mediaPlayer.stop()方法結束子執行緒阻塞,銷燬掉當前的播放器,重新初始化播放器。延遲1s後播放新的歌曲。這裡做延遲的原因是為了防止介面頻繁點選新的歌曲。如果不延時,將會在初始化的地方出現ANR。try { mediaPlayer.reset(); mediaPlayer.setDataSource(path); mediaPlayer.prepare(); mediaPlayer.start(); catch (IllegalArgumentException e) { } catch (SecurityException e) { } catch (IllegalStateException e) { } catch (IOException e) { } catch (NullPointerException e) { }
//讓阻塞的播放執行緒報異常結束註冊
mediaPlayer.stop();
//這裡必須起執行緒呼叫release不然多次呼叫之後,會出現ANR
final MediaPlayer releaseMediaPlayer = mediaPlayer;
new Thread() {
public void run() {
releaseMediaPlayer.release();
};
}.start();
//重新初始化的原因是因為丟擲異常之後播放器內部會出現問題,幾次之後就報錯誤無法播放。
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.setOnPreparedListener(this);
}
catch (Exception e) {
e.printStackTrace();
}
3.MediapPalyer OnPreparedListener的作用
因為我是呼叫的mediaPlayer.prepare();方法,所以就沒有在OnPreparedListener回撥方法Onprepared方法中呼叫mediaPlayer.start()方法進行播放。在部分的android裝置上也是沒有問題的。但是經過測試有個裝置會偶現mediaPlayer(-38,0)錯誤(這裡錯誤是在執行prepare()的方法時出現,還沒有執行到start()方法)。通過log也發現。如果順序執行,mediaPlayer.start()方法的確是執行onPrepared方法之前。然後我就把mediaPlayer.start()寫到Onprepared()的回撥方法中。經過測試不會出現這個偶現的問題。在這裡問題解決方案存在疑問,也請大神們指點一下。
4.mediaPlayer.getCurrentPosition()播放過程中會出現的誤差
為了實現一個當播放器播放到最大緩衝的位置(播放器之後不能再播放)提示“載入中”。這裡簡單的實現了一下,大致的方案如下:在重新整理播放進度的方法中,判斷當前的播放進度和上一次的播放進度。如果當前精度小於等於上一次的播放進度,就提示“載入中”。經過測試發現,網路較差時的確存在本次播放進度比上一次播放進度小的問題,差值有時候會很大會有幾s左右。具體原因不可知。這裡也請大家提供合理的解決方案。