//继续完善音乐播放器demo

相关文章:
android:使用Messenger进行进程间通信(一):http://www.cnblogs.com/happyhacking/p/5318418.html
android:使用RemoteView自定义Notification:http://www.cnblogs.com/happyhacking/p/5318529.html

activity => service => notification

在添加了Notification之后,出现一个问题,即通过activity和notification都可以实现对service中方法的调用,
然而目前两者并不能同步.由于之前已经实现了从activity到service的进程间通信,所以当在activtiy中进行操作时,
相应的在service中使用handler更新notification的内容即可.

  class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mActivityMessenger = msg.replyTo;
            switch (msg.what) {
                case 0:
                    mMediaPlayer.stop();
                    i  = msg.arg1;
                    mMediaPlayer = MediaPlayer.create(MusicService.this, mMusicDatas.get(i).getSrc());
                    if(isPlaying) {
                        mMediaPlayer.start();
                    }

                    //更新notification显示的内容
                    mRemoteViews.setTextViewText(R.id.music_name, mMusicDatas.get(i).getName());
                    mRemoteViews.setTextViewText(R.id.singer_name, mMusicDatas.get(i).getSinger());
                    mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
                    break;
                case 1:
                    if(msg.arg1==1){
                        isPlaying =false;
                        mMediaPlayer.pause();
                          
                        //更新notification显示的内容
                        mRemoteViews.setImageViewResource(R.id.btn_play, R.drawable.note_btn_play);
                        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
                    } else {
                        isPlaying = true;
                        i = msg.arg2;
                        mMediaPlayer = MediaPlayer.create(MusicService.this, mMusicDatas.get(i).getSrc());
                        mMediaPlayer.start();

                        //更新notification显示的内容
                        mRemoteViews.setImageViewResource(R.id.btn_play, R.drawable.note_btn_pause);
                        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
                    }
                    break;
                default:
                    break;
            }
        }
    }

notification => service => activity

在谷歌的官方文档中有以下描述:

If you want the service to respond, then you need to also create a Messenger in the client. 
Then when the client receives the onServiceConnected() callback, it sends a Message to the service 
that includes the client's Messenger in the replyTo parameter of the send() method.

个人理解是:
要实现service到activity的通信,需要在activity(client)也创建一个Messenger,并且在onServiceConnected()
方法中将这个messenger实例作为replyTo的参数send到service.

activity中的处理:

①创建activity自身的messenger,用来处理service发送过来的message
②在ServiceConnection实例的onServiceConnected()回调方法中将activity的messenger作为msg.replyTo的参数send给service

   //创建activity自身的messenger
    private  Messenger mActivityMessenger = new Messenger(new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case CODE:
                    mIndex = msg.arg1;
                    setMusicNameAndSingerName(mIndex);
                    if(msg.arg2 == 1) {
                        mPlayBtn.setBackgroundResource(R.drawable.desk_pause);
                    } else {
                        mPlayBtn.setBackgroundResource(R.drawable.desk_play);
                    }
            }
        }
    });


    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mMessenger = new Messenger(service);

            //注意这里紧接着要send一次,目的是防止首先操作的是notification,而这时service还没有得到activity的messenger,导致service->activity的通信失败.
            Message message = Message.obtain();
            message.replyTo = mActivityMessenger;
            try {
                mMessenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

service中的处理

在自定义hangdler中接收activity发送过来的messenger.

 class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            
            //获取client的messenger
            mActivityMessenger = msg.replyTo;
            
            switch (msg.what) {
              //...
            }
        }
    }

当notification中的点击事件发生时,调用以下方法,向activity发送msg

    //service->activity
    private void sendToActivity() {
        Message message = Message.obtain();
        message.what = MainActivity.CODE;
        message.arg1 = i;
        message.arg2 = (isPlaying == true)?1:2;
        try {
            mActivityMessenger.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

如此一来,就实现了activity和service之间的进程间的双向通信.

基本原理如下图所示:

图中:黑字实线是activity和service的绑定过程中相互发送messenger的过程.
红字虚线是进程间相互通信的过程.

需要强调的是:
在bindService()成功后,要立即将activity的messenger发送给service,否则,如果在此操作之前,操作notification,
由于此时service中还没有activity的messenger,将无法将notification的操作同步到activity中.

github地址:https://github.com/zhangbz/MusicPlayer

 posted on 2016-03-25 12:26  zhangbz  阅读(747)  评论(0编辑  收藏  举报