對MediaPlayer的錯誤使用總結

阿壯發表於2018-07-29

近期做的一個專案,裡面涉及到很多音訊播放,於是在網上找一篇MeidialPlayer的程式碼使用,功能開發完畢,提交測試之後,發現音訊播放幾十次之後就停止了,無法播放,必須退出Activity重新進入才可以再次播放;於是從頭開始根據google官方關於MediaPalyer的介紹看了一遍,很快就解決的問題。

首先來看網站找的程式碼(只貼核心程式碼)

    public void startPlay(String path) {
        stopPlay();
        MediaPlayer mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnPreparedListener(this);
        mediaPlayer.setOnCompletionListener(this);
        mediaPlayer.setOnErrorListener(this);
        try {
            mediaPlayer.setDataSource(path);
            mediaPlayer.prepareAsync();
        } catch (IOException e) {
            e.printStackTrace();
            if(listener != null) {
                listener.onError(String.format("MediaPlayer setDataSource Error by %s", e.getMessage()));
            }
        }
    }
  
    public void stopPlay() {
        if(mediaPlayer != null && !isRelease) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }
  
      @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        this.mediaPlayer = mediaPlayer;
        this.mediaPlayer.start();
        this.isRelease = false;
        if(listener != null) {
            listener.onPrepared();
        }
    }

    @Override
    public void onCompletion(MediaPlayer mediaPlayer) {
        if(this.mediaPlayer != null) {
            if(isRelease) {
                this.mediaPlayer.release();
                isRelease = true;
            }
            mediaPlayer = null;
        }
        if(listener != null) {
            listener.onCompletion();
        }
    }
複製程式碼

我先說說它的實現:把MediaPlayer做一層封裝,把MediaPlayer做了全域性變數,首先在啟動播放之前,先關閉(釋放資源並置空)上一個音訊播放,然後初始化MediaPlayer和一些監聽;當MediaPlayer到達準備狀態之後,把MediaPlayer做成全域性引用,並設定是否釋放音訊資源的狀態,然後當音訊播放完成之後,再完成回撥中執行釋放操作;這樣使用相當於頻繁的建立MediaPlayer和釋放;如果只是偶爾播放一下音訊應該不會出現問題,但如果做需要播放大量音訊的專案,就會報錯;

要解決這個問題,我們先來看看google官方是如何教我們使用MediaPlayer的:

對MediaPlayer的錯誤使用總結

上面很清楚的可以看到MediaPlayer各個狀態的切換: 1、Idle:空閒狀態,使用者通過new建立MediaPlayer或者呼叫reset()都可進入此狀態,注意該狀態下不可執行prepare()、start()等方法; 2、Initialized:初始化狀態,對處於空閒狀態下的MediaPlayer呼叫setDataSource()即可,該狀態下使用者可執行prepare()、prepareAsync()方法; 3、Prepared:準備狀態,設定播放資源後,呼叫prepare()或prepareAsync()方法進入準備播放狀態,使用者可以通過呼叫start()方法來播放音訊(注意如果是網路地址必須在onPrepared()中start()); 4、Started:播放狀態,執行start()之後,開始播放音訊,播放完成後,執行OnComplete()回撥,呼叫paused()進入暫停狀態,呼叫start()可以恢復播放狀態; 5、Stopped:停止狀態; 6、Paused:暫停狀態;

public class PlayUtils implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {

    private MediaPlayer mediaPlayer;
    private OnPlayerListener listener;

    public PlayUtils() {
        mediaPlayer = new MediaPlayer();
    }

    public void setOnPlayerListener(OnPlayerListener onPlayerListener) {
        this.listener = onPlayerListener;
    }

    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        mediaPlayer.start();
        if(listener != null) {
            listener.onPrepared();
        }
    }

    @Override
    public void onCompletion(MediaPlayer mediaPlayer) {
        if(listener != null) {
            listener.onCompletion();
        }
    }

    @Override
    public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
        if(listener != null) {
            listener.onError(String.format("MediaPlayer error what %d error %d", i, i1));
        }
        return true;
    }

    public interface OnPlayerListener {
        void onPrepared();

        void onCompletion();

        void onError(String error);
    }

    public void startPlay(String path) {
        if(mediaPlayer == null) {
            mediaPlayer = new MediaPlayer();
        }else {
            stopPlay();
        }
        mediaPlayer.setOnPreparedListener(this);
        mediaPlayer.setOnCompletionListener(this);
        mediaPlayer.setOnErrorListener(this);
        try {
            mediaPlayer.setDataSource(path);
            mediaPlayer.prepareAsync();
        } catch (IOException e) {
            e.printStackTrace();
            if(listener != null) {
                listener.onError(String.format("MediaPlayer setDataSource Error by %s", e.getMessage()));
            }
        }
    }

    public void stopPlay() {
        if(mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.reset();
        }
    }

    public boolean isPlaying() {
        return mediaPlayer != null && mediaPlayer.isPlaying();
    }

    public void onDestroy() {
        if(mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }
}
複製程式碼

以上就是使用MediaPlayer的一點小結,如有疑問或錯誤,可在下方評論區留言,謝謝~

相關文章