MediaPlayer+MediaPlayerController+MediaPlayer.OnBufferingUpdateListener实现音乐播放器

在Android开发中渐渐发现每一个类只负责自己的模块,类之间的耦合性很低。每一个类只负责自己的模块,但不同的类进行组合就可以创建一个功能强大的应用;

下面通过一个音乐播放器来体验下这个思想:
我们之前可能学过如何通过MediaPlayer来播放res/raw、assets中的原声文件、网络中的文件等等。在这里不做介绍,感兴趣的自己查资料吧!
但在以前我们更多的使用Button+MediaPlayer.start()/MediaPlayer.stop()/MediaPlayer.pause()等方法,来控制音乐的暂停和停止。其实Android为我们提供了MediaContraller来进行暂停、停止的请求。

1.MediaPlayerController的源码

public interface MediaPlayerControl {
        void    start();
        void    pause();
        int     getDuration();
        int     getCurrentPosition();
        void    seekTo(int pos);
        boolean isPlaying();
        int     getBufferPercentage();
        boolean canPause();
        boolean canSeekBackward();
        boolean canSeekForward();
    }

其实它就是一个接口,当我们通过MediaController来控制音乐的播放时,就会调用我们所实现它的方法。

2、MediaPlayer.OnBufferingUpdateListener

public interface OnBufferingUpdateListener
    {
        /**
         * Called to update status in buffering a media stream received through
         * progressive HTTP download. The received buffering percentage
         * indicates how much of the content has been buffered or played.
         * For example a buffering update of 80 percent when half the content
         * has already been played indicates that the next 30 percent of the
         * content to play has been buffered.
         *
         * @param mp      the MediaPlayer the update pertains to
         * @param percent the percentage (0-100) of the content
         *                that has been buffered or played thus far
         */
        void onBufferingUpdate(MediaPlayer mp, int percent);
    }

监听事件,网络流媒体的缓冲监听。这个方法与上个接口中的方法int getBufferPercentage()进行结合使用;

3、下面通过一个Demo来看看:

(1)MediaController是怎样与MediaPlayerController结合
(2)MediaPlayerController是怎样与MediaPlayer结合

1、布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:id="@+id/root"
    >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Playing..." 
        android:id="@+id/textview"
        android:gravity="center_horizontal"
        android:textSize="24sp"
        />
    <ImageView 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="centerInside"
        android:id="@+id/coverImage"
        android:src="@drawable/zjl"
        />

</LinearLayout>

2、Activity

public class MainActivity extends Activity implements MediaPlayerControl,MediaPlayer.OnBufferingUpdateListener{

    private MediaPlayer mediaPlayer;
    private MediaController controller;
    private int bufferPercentage = 0;
    private AssetFileDescriptor afd = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mediaPlayer = new MediaPlayer();
        controller = new MediaController(this);
        controller.setAnchorView(findViewById(R.id.root));

    }
    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        try {
            afd = getAssets().openFd("beautiful.mp3");
            mediaPlayer.setDataSource(afd.getFileDescriptor());
            mediaPlayer.setOnBufferingUpdateListener(this);
            mediaPlayer.prepare();

            //他们要放到
            controller.setMediaPlayer(this);
            controller.setEnabled(true);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        if(mediaPlayer.isPlaying()){
            mediaPlayer.stop();
        }
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        if(null != mediaPlayer){
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        controller.show();
        return super.onTouchEvent(event);
    }
    @Override
    public void start() {
        if(null != mediaPlayer){
            mediaPlayer.start();
        }
    }

    @Override
    public void pause() {
        if(null != mediaPlayer){
            mediaPlayer.pause();
        }
    }

    @Override
    public int getDuration() {
        return mediaPlayer.getDuration();
    }

    @Override
    public int getCurrentPosition() {
        // TODO Auto-generated method stub
        return mediaPlayer.getCurrentPosition();
    }

    @Override
    public void seekTo(int pos) {
        // TODO Auto-generated method stub
        mediaPlayer.seekTo(pos);
    }

    @Override
    public boolean isPlaying() {
        // TODO Auto-generated method stub
        if(mediaPlayer.isPlaying()){
            return true;
        }
        return false;
    }

    @Override
    public int getBufferPercentage() {
        // TODO Auto-generated method stub
        return bufferPercentage;
    }

    @Override
    public boolean canPause() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean canSeekBackward() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean canSeekForward() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
        // TODO Auto-generated method stub
        bufferPercentage = percent;
    }
}

因为MediaController 是单独的窗口,所以不能在onCreate()中调用MediaController. show(),否则会导致一个致命的异常。MediaController 默认是隐藏的并且由用户激活。本例中,我们覆写了Activity的onTouchEvent()方法,当用户单击屏幕就会显示MediaController。除非show()方法传入的参数是0,否则它都会在参数指定的时间之后消隐。如果调用show()时没有传入任何参数,将使用默认的超时时间,大概是3 秒钟。

在实现MediaController 时有一个技巧。这个控件是漂浮在它所在窗口中活动的view之上的,而且一次只显示几秒钟。因此,我们没有在content view 的XML 布局中初始化它,而是使用代码进行初始化。MediaController 和contentview 之间的纽带就是setAnchorView(),该方法还决定了MediaController 在屏幕中的显示位置。


4、我们同样可以通过MediaController+VideoView控制视频的播放

观察VideoView源码我们会发现

public class VideoView extends SurfaceView implements MediaPlayerControl {
    ...
}

VideoView已经实现了MediaPlayerControl,所以我们在控制视频的播放上会很简单:

videoView.setVideoPath(videoPath.getAbsolutePath());
videoView.setMediaController(mediaController);
mediaController.setMediaPlayer(videoView);
videoView.requestFocus();

下篇博客我将详细介绍下MediaPlayer的生命周期。

发布了38 篇原创文章 · 获赞 45 · 访问量 9万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览