Android媒体播放:MediaPlayer

来源:互联网 发布:大数据精准营销的案例 编辑:程序博客网 时间:2024/04/30 20:21

一、基本的类
MediaPlayer:负责播放音频和视频。
AudioManager:用来管理音频资源和音频输出。

二、使用MediaPlayer
播放一个从ContentResolver获得的系统Uri:

// 初始化uriUri myUri = ....; MediaPlayer mediaPlayer = new MediaPlayer();// 设置流媒体的类型,便于系统依类型控制音量(铃声音量、多媒体音量等)mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);// 设置数据源mediaPlayer.setDataSource(getApplicationContext(), myUri);mediaPlayer.prepare();mediaPlayer.start();

播放网络流媒体:

// 注意:这个音频文件必须能够渐进式下载String url = "http://........"; MediaPlayer mediaPlayer = new MediaPlayer();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource(url);// 可能需要较长时间,比如缓冲mediaPlayer.prepare();mediaPlayer.start();

播放应用的内置raw资源:

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);// create()中已调用prepare(),不必再调用后者mediaPlayer.start(); 

三、异步准备资源
prepare()可能会花较长时间去提取、解码,为了避免阻塞UI主线程,Android提供了prepareAsync()来实现异步准备。此方法会在后台开始准备并立即返回,当准备完毕时,系统会调用onPrepared()

private class OnPreparedListener implements MediaPlayer.OnPreparedListener {    @Override    public void onPrepared(MediaPlayer mp) {        // 异步准备完毕后,开始播放        mp.start();    }}// 如果是同步调用prepare(),发生错误时系统会直接抛出异常。// 而异步调用prepareAsync()则需要监听错误的发生并处理。private class OnErrorListener implements MediaPlayer.OnErrorListener {    /**     * 错误发生时的回调方法。     *     * 返回true表示错误已处理;     * 如果返回false,或者未设置OnErrorListener,     * 将会调用OnCompletionListener。     */    @Override    public boolean onError(MediaPlayer mp, int what, int extra) {        // 处理错误代码略        ...        // 此时MediaPlayer已处于Error状态,必须reset()        mp.reset();        return true;    }}Uri myUri = ....;MediaPlayer mediaPlayer = new MediaPlayer();// 设置异步准备监听器mediaPlayer.setOnPreparedListener(new OnPreparedListener());// 设置错误监听器mediaPlayer.setOnErrorListener(new OnErrorListener());mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource(getApplicationContext(), myUri);// 异步准备mediaPlayer.prepareAsync();

四、管理MediaPlayer状态
MediaPlay是基于状态(state)的播放器。某些操作仅当播放器处在特定的状态才有效。如果操作时状态不对,系统会抛出异常或导致其他未期望的行为。具体请看下图:
MediaPlayer状态图

五、释放MediaPlayer
MediaPlayer占用着大量宝贵的系统资源。当用不着时(比如在未播放的情况下Activity进入onStop()),可调用release()来释放系统给它分配的资源:

mediaPlayer.release();mediaPlayer = null;

六、处理音频焦点
可能会有若干个应用于某个时刻正在或者准备要播放音频,若都申请音频焦点则可有序竞争避免同时播放降低用户体验。

private class OnAudioFocusChangeListener     implements AudioManager.OnAudioFocusChangeListener {    @Override    public void onAudioFocusChange(int focusChange) {        switch (focusChange) {            // 获得音频焦点:            case AudioManager.AUDIOFOCUS_GAIN:                if (mMediaPlayer == null) initMediaPlayer();                else if (!mMediaPlayer.isPlaying() && mIsPrepared) {                    mMediaPlayer.start();                }                mMediaPlayer.setVolume(1.0f, 1.0f);                break;            // 较长时间地失去音频焦点:            case AudioManager.AUDIOFOCUS_LOSS:                if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();                mMediaPlayer.release();                mMediaPlayer = null;                break;            // 短暂地失去音频焦点:            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:                if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();                break;            // 短暂地失去音频焦点,但可以低音量播放:            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:                if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f);                break;        }    }}// 如果系统版本在Android 2.2(API 8)之上,// 则可通过AudioManager来处理音频焦点,// 以获得更好的用户体验。if (Build.VERSION.SDK_INT >= 8) {    AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);    OnAudioFocusChangeListener onAudioFocusChangeListener =         new OnAudioFocusChangeListener();    // AUDIOFOCUS_GAIN:常驻型焦点。还有短暂、独占等。    int result = audioManager.requestAudioFocus(onAudioFocusChangeListener,        AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);    if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {        // 没法获得音频焦点    } else {        // 已获得音频焦点,可以开始播放        ...        // 播放结束后,可以放弃音频焦点:        audioManager.abandonAudioFocus(            onAudioFocusChangeListener);    }}

七、处理AUDIO_BECOMING_NOISY
当耳机被拔出或断开连接时,系统发出这个Intent,并转换至内置扬声器播放。通过接收它并通知播放服务暂停或者降低音量,可以避免扬声器过于嘈杂而降低用户体验。
在Activity中动态注册一个广播接收器:

private NoisyIntentReceiver mNoisyIntentReceiver = new MusicIntentReceiver();@Overrideprotected void onCreate(Bundle savedInstanceState) {    ...    IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);    registerReceiver(mNoisyIntentReceiver, intentFilter);}@Overrideprotected void onDestroy() {    ...    unregisterReceiver(mNoisyIntentReceiver);}

广播接收器的代码:

public class NoisyIntentReceiver extends BroadcastReceiver {    private PlaybackService.PlaybackBinder mPlaybackBinder = null;    public void setPlaybackBinder(        PlaybackService.PlaybackBinder playbackBinder) {        mPlaybackBinder = playbackBinder;    }    @Override    public void onReceive(Context context, Intent intent) {        if (intent.getAction().equals(            AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {            if (mPlaybackBinder != null &&                 mPlaybackBinder.isPlaying()) {                mPlaybackBinder.pause();            }        }    }}

八、使用硬件音量键来控制音量
默认情况下,音量键可控制当前播放的音频流。如果前台Activity此时未播放任何音频,那么按下音量键控制的是铃声音量。在Activity中可做如下设置:

@Overwriteprotected void onCreate(Bundle savedInstanceState) {    ...    setVolumeControlStream(AudioManager.STREAM_MUSIC);    ...}

使得当Activity可见时,它可以按用户的预期来调整Activity的音量。

九、使用耳机播放控制键来控制音频播放
每当按下耳机播放控制键(包括播放、暂停、停止、下一曲、上一曲)时,系统都会广播ACTION_MEDIA_BUTTON。
在Activity中动态注册一个广播接收器:

private RemoteControlReceiver mRemoteControlReceiver = new RemoteControlReceiver();private void onGetAudioFocus() {    IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);    registerReceiver(mRemoteControlReceiver, intentFilter);}private void onLoseAudioFocus() {    unregisterReceiver(mRemoteControlReceiver);}

广播接收器的代码:

public class RemoteControlReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {            KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);            switch (keyEvent.getKeyCode()) {                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:                    // ...                    break;                case KeyEvent.KEYCODE_MEDIA_PLAY:                    // ...                    break;                case KeyEvent.KEYCODE_MEDIA_PAUSE:                    // ...                    break;                case KeyEvent.KEYCODE_MEDIA_STOP:                    // ...                    break;                case KeyEvent.KEYCODE_MEDIA_NEXT:                    // ...                    break;                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:                    // ...                    break;                case KeyEvent.KEYCODE_MEDIA_REWIND:                    // ...                    break;                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:                    // ...                    break;            }        }    }}

参考资料:

Android > Developer > API Guides > Media Playback
http://developer.android.com/intl/zh-cn/guide/topics/media/mediaplayer.html

Android > Developer > Training > Controlling Your App’s Volume and Playback
http://developer.android.com/intl/zh-cn/training/managing-audio/volume-playback.html

0 0
原创粉丝点击