Android MediaPlay的一个简单工具类及几点注意

步骤一:代码如下

import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ProgressBar;
import android.widget.SeekBar;

import java.io.IOException;

/**
 * Created by imac on 2018/8/28.
 */

public class MediaUtil implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener,SeekBar.OnSeekBarChangeListener {

    private static final String TAG = "LOG_MediaUtil";
    private static final int INTERNAL_TIME = 1000;

    private Context mContext;


    private MediaPlayer mediaPlayer;

    private SeekBar progressBar;


    public void setProgressBar(SeekBar progressBar) {
        this.progressBar = progressBar;
        this.progressBar.setOnSeekBarChangeListener(this);
    }

    private final int MSG_UPDATA_PROGRESS = 0x10001;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_UPDATA_PROGRESS:
                    Log.i(TAG,"MSG_UPDATA_PROGRESS");
                    // 展示给进度条和当前时间
                    if (mediaPlayer == null){
                        return;
                    }
                    int progress = mediaPlayer.getCurrentPosition();
                    if (progressBar != null){
                        Log.i(TAG,"MSG_UPDATA_PROGRESS progress = " + progress);
                        progressBar.setProgress(progress);
                    }
                    updateProgress();
                    break;
                default:
                    break;
            }
            super.handleMessage(msg);
        }
    };

    public MediaUtil(Context mContext) {
        this.mContext = mContext;
        mediaPlayer = new MediaPlayer();
    }


    public void playMusic(final String musilcUrl) {
//        String url = "http://m10.music.126.net/20180829015325/2d0c208babcda73d3e54e9694daf5cac/ymusic/d60e/d53a/a031/1578f4093912b3c1f41a0bfd6c10115d.mp3";
        Log.i(TAG, "playMusic: enter");
        Uri musicUri = Uri.parse(musilcUrl);
//        Uri musicUri = Uri.parse(url);
        Log.i(TAG, "playMusic: musicUri = " + musicUri);
        if (mediaPlayer.isPlaying()) {
            Log.i(TAG, "playMusic: isPlaying");
            stopMusic();
        }

        try {

            mediaPlayer.setDataSource(mContext, musicUri);
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.prepareAsync();
            mediaPlayer.setLooping(true);
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void stopMusic() {
        Log.i(TAG, "stopMusic: enter");
        if (mediaPlayer == null) {
            Log.i(TAG, "stopMusic: is null mediaPlayer");
            return;
        }
        mediaPlayer.reset();
        mediaPlayer.stop();
    }


    @Override
    public void onPrepared(MediaPlayer mp) {
        Log.i(TAG, "onPrepared: enter getDuration is =" + mp.getDuration());
        mp.start();
        updateProgress();
        progressBar.setMax(mp.getDuration());
    }


    public void releaseMediaPlayer() {
        Log.i(TAG, "releaseMediaPlayer: enter");
        if (mediaPlayer != null) {
            mHandler.removeMessages(MSG_UPDATA_PROGRESS);
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }

    @Override
    public void onCompletion(MediaPlayer mp) {

    }


    // 每间隔1s通知更新进度
    private void updateProgress() {
        // 使用Handler每间隔1s发送一次空消息,通知进度条更新
        Message msg = Message.obtain();// 获取一个现成的消息
        msg.what = MSG_UPDATA_PROGRESS;
        mHandler.sendMessageDelayed(msg, INTERNAL_TIME);
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if(mediaPlayer != null && fromUser){
            mediaPlayer.seekTo(progress);
        }
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }
}

步骤二:注意点
1.勿忘mediaPlayer.reset();
当媒体已经播放了的时候,如果再直接调用mediaPlayer.stop()暂停音乐,而不调用mediaPlayer.reset();直接使用setDataSource()重新播放,则会出现IllegalStateException 异常。
源码如下:

    /**
     * Sets the data source as a content Uri.
     *
     * @param context the Context to use when resolving the Uri
     * @param uri the Content URI of the data you want to play
     * @throws IllegalStateException if it is called in an invalid state
     */
    public void setDataSource(@NonNull Context context, @NonNull Uri uri)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        setDataSource(context, uri, null, null);
    }

2.建议使用 mediaPlayer.prepareAsync();
prepare()会阻塞UI,容易造成卡顿,建议使用异步的prepareAsync();
源码:

    /**
     * Prepares the player for playback, synchronously.
     *
     * After setting the datasource and the display surface, you need to either
     * call prepare() or prepareAsync(). For files, it is OK to call prepare(),
     * which blocks until MediaPlayer is ready for playback.
     *
     * @throws IllegalStateException if it is called in an invalid state
     */
    public void prepare() throws IOException, IllegalStateException {
        _prepare();
        scanInternalSubtitleTracks();

        // DrmInfo, if any, has been resolved by now.
        synchronized (mDrmLock) {
            mDrmInfoResolved = true;
        }
    }
    /**
     * Prepares the player for playback, asynchronously.
     *
     * After setting the datasource and the display surface, you need to either
     * call prepare() or prepareAsync(). For streams, you should call prepareAsync(),
     * which returns immediately, rather than blocking until enough data has been
     * buffered.
     *
     * @throws IllegalStateException if it is called in an invalid state
     */
    public native void prepareAsync() throws IllegalStateException;

使用prepareAsync()时,实现OnPreparedListener接口,当资源准备好之后,调用mp.start();播放媒体

3.进度条如代码所示,不细说了。主要实现SeekBar.OnSeekBarChangeListener 接口,进行拖动进度条时进行监听。

步骤三:进一步思考

由于Android 原生的MediaPlay没有缓存,重复播放相同音乐时会造成重复加载网络资源。这部分可以考虑缓存到本地,减少流量的消耗以及加快播放速度。

猜你喜欢

转载自blog.csdn.net/u014132820/article/details/82229960