startService和onBinderService混合开发音乐播放器

首先你你需要知道MediaPlayer这个类的一些方法:

  • int getDuration():获取流媒体的总播放时长,单位是毫秒。
  • int getCurrentPosition():获取当前流媒体的播放的位置,单位是毫秒。
  • void seekTo(int msec):设置当前MediaPlayer的播放位置,单位是毫秒。
  • void setLooping(boolean looping):设置是否循环播放。
  • boolean isLooping():判断是否循环播放。
  • boolean isPlaying():判断是否正在播放。
  • void prepare():同步的方式装载流媒体文件。
  • void prepareAsync():异步的方式装载流媒体文件。
  • void release ():回收流媒体资源。
  • void setAudioStreamType(int streamtype):设置播放流媒体类型。
  • void setWakeMode(Context context, int mode):设置CPU唤醒的状态。
  • setNextMediaPlayer(MediaPlayer next):设置当前流媒体播放完毕,下一个播放的MediaPlayer。

注意一下两点

  1. 在使用MediaPlayer播放一段流媒体的时候,需要使用prepare()或prepareAsync()方法把流媒体装载进MediaPlayer,才可以调用start()方法播放流媒体。                 
  2. setAudioStreamType()方法用于指定播放流媒体的类型,它传递的是一个int类型的数据,均以常量定义在AudioManager类中, 一般我们播放音频文件,设置为AudioManager.STREAM_MUSIC即可。

在播放下一首歌曲的时候需要释放MediaPlayer的资源:

if (mediaPlayer != null && mediaPlayer.isPlaying()) {
        mediaPlayer.stop();
        mediaPlayer.release();
        mediaPlayer = null;
    }

然后就是关于BinderService:

  • 先看一下按下Back键之后Activity的生命周期:onPause()-->onStop()-->onDestory()-->onCreate()-->onStart()-->onResum();

  • BinderService的存活于绑定的Activity有关,当与之绑定的Activity被销毁的时候,Service也会销毁,根据生命周期,我们就可以知道,当你按下Back键的时候,Service也会销毁,这样音乐就会停止播放,但是我们使用的大多数音乐播放器软件都按下Back键之后依旧在播放,所以,就有了我们的startServuce()和binderService()混合开发,因为startService()的生命周期与activity无关。

  • 我们的主要逻辑是,用startService播放音乐,用binderService()控制音乐的播放。

  • startService很常见,就不说了,你需要知道binderService的使用,其实binderService就是用一个继承与BInder的MyBinder的类,作为一个中间对象,在Activity中对Service中的方法进行调用,从而实现控制。

下面我们开始编写我们的音乐播放器

创建一个MusicItem类记录一些音乐的信息

public class MusicItem {
    public String name;
    public String data;
    public String artist;
    public long time;
}

请求读写权限并且获取手机上的所有音频文件

private void initData(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (PackageManager.PERMISSION_DENIED == checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)){
                requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},0);
            }
        }

        itemList = new ArrayList<>();

        new Thread(){
            @Override
            public void run() {
                super.run();
                ContentResolver resolver = mContext.getContentResolver();
                Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                String[] objs ={
                        MediaStore.Audio.Media.DISPLAY_NAME,
                        MediaStore.Audio.Media.DATA,
                        MediaStore.Audio.Media.ARTIST,
                        MediaStore.Audio.Media.DURATION,
                };

                Cursor cursor = resolver.query(uri,objs,null,null,null);
                if (cursor !=null){
                    while (cursor.moveToNext()){
                        MusicItem musicItem = new MusicItem();
                        itemList.add(musicItem);

                        String name = cursor.getString(0);
                        musicItem.name = name;
                        String data = cursor.getString(1);
                        musicItem.data = data;
                        String aritst = cursor.getString(2);
                        musicItem.artist = aritst;
                        long time = cursor.getLong(3);
                        musicItem.time = time;
                    }
                  cursor.close();
                }
                handler.sendEmptyMessage(0);
            }
        }.start();

    }

获取到手机上的所有的音频文件之后,发送一个handler消息,将musicItem的集合itemList中的数据显示在Adapter上(Adapter的代码这里不拿出来说了,很见到的)

创建一个MusicService类,继承与Service

这个类用来后台播放音乐

public class MusicService extends Service {

    private MediaPlayer player;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    public void onPause(){
        player.pause();
    }
    
    public void onStart(){
        player.start();
    }
    
    public void openAudio(String uri) throws IOException {
        if (player != null && player.isPlaying()){
            player.stop();
            player.release();
            player = null;
        }
        player = new MediaPlayer();
        player.setAudioStreamType(AudioManager.STREAM_MUSIC);
        try {
            player.setDataSource(uri);
            player.prepare();
            player.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public class MyBinder extends Binder{
        MusicService getService(){
            return MusicService.this;
        }
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        player.stop();
        player.reset();
        player.release();
    }
}
  • MyBinder是Activity与MusicService进行通信的中间对象(这里只实现了播放和暂停的功能)

绑定MusicSerivce

下面是Activity的onCreate()方法:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        mContext = this;

        lvList = (ListView) findViewById(R.id.lv_list);
        Button start = (Button) findViewById(R.id.start);
        Button pasue = (Button) findViewById(R.id.pause);
        pasue.setOnClickListener(this);
        start.setOnClickListener(this);
        Intent intent = new Intent(MainActivity.this,MusicService.class);
        startService(intent);
        bindService(intent,conn,BIND_AUTO_CREATE);
        initData();
    }

绑定Service:

private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            service1 = ((MusicService.MyBinder) service).getService();
        }

        @Override

        public void onServiceDisconnected(ComponentName name) {

        }
    };

点击ListView中的Item的时候播放音乐

实现暂停和播放:

private android.os.Handler handler = new android.os.Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (itemList != null && itemList.size()>0){
                MusicAdapter adapter = new MusicAdapter(mContext,itemList);
                lvList.setAdapter(adapter);
                lvList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                        try {
                            service1.openAudio(itemList.get(position).data);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }
    };
@Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.start:
                service1.onStart();
                break;

            case R.id.pause:
                service1.onPause();
                break;

        }
    }
  • 当绑定成功的时候,返回的是一个MusicService对象,拿着这个Service对象就能对MusicService中的方法进行调用了。
  • 首先startService,然后在binderService让Activity与Service之间进行通信,然Activity通过MyBinder对象对Service中的方法进行调用。

Service的销毁

在Activity中的onDestory()方法中对MusicService进行取消绑定:

@Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }

记得添加读写权限

posted @ 2017-03-14 22:56  Godfunc  阅读(514)  评论(0编辑  收藏  举报