1. 程式人生 > >Android MediaPlayer 播放器網路音訊播放總結

Android MediaPlayer 播放器網路音訊播放總結

        在近期的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)的時候返回各種不同的錯誤。
      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) {
        }
        2.因為第一種方案問題更多,之後我還是繼續使用mediaPlayer.prepare()方法。想通過執行緒的中斷來解決問題。因為是阻塞在MediapPalyer的內部只能通過兩種方案,一種就是讓MediapPalyer內部報異常,一種就是強制結束執行緒。這裡嘗試第一種方案的時候發現。當播放執行緒阻塞的時候mediaPlayer.prepare(),在主執行緒呼叫mediaPlayer.stop()方法可以讓prepare方法報IllegalStateException(經過測試這個是必現的,API中有stop方法呼叫合法狀態)。解決方案具體如下:當播放新歌曲的時候,如果發現播放執行緒阻塞了,也就是當前的狀態是preparing狀態,主執行緒中呼叫mediaPlayer.stop()方法結束子執行緒阻塞,銷燬掉當前的播放器,重新初始化播放器。延遲1s後播放新的歌曲。這裡做延遲的原因是為了防止介面頻繁點選新的歌曲。如果不延時,將會在初始化的地方出現ANR。
            //讓阻塞的播放執行緒報異常結束註冊
            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左右。具體原因不可知。這裡也請大家提供合理的解決方案。