• android:使用Messenger进行进程间通信(一)


    Messenger简介

    Messenger和AIDL是实现进程间通信(interprocess communication)的两种方式.
    实际上,Messenger的实现其实是对AIDL的封装.
    Messenger适合于多进程单线程,AIDL适合于多进程多线程,需要开发者自己实现线程安全.
    google官方文档指出对于大部分的程序,service不需要执行多线程,所以应该首先考虑使用Messenger.

    为什么需要进程间通信?

    因为不同进程之间的数据是不共享的.

    实践(以音乐播放器demo为例)

    关键词: bind + messenger + handler

    step1 (AndroidManifest.xml)在AndroidManifest.xml中注册service,并设置为其android:process属性赋值

    注意① 忘记注册service的话,程序不会响应,但是也不会崩溃的...
    注意② 此处设置该service为一个全局进程,意即不同应用程序可以共享该进程,若process以":"开头,则表示其为该应用程序的私有进程.

            <service android:name=".MusicService"
                android:process="com.example.janiszhang.musicplayer.service.process"/>
    

    step2 (MusicService)在service中实现一个继承Handler的子类(),用于处理由activity发来的message

     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();
                        }
                        //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();
                            //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();
                            //mRemoteViews.setImageViewResource(R.id.btn_play, R.drawable.note_btn_pause);
                            //mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    
    

    step3 (MusicService)实例化自定义的handler,作为参数,创建一个Messenger

        Messenger mMessenger = new Messenger(new IncomingHandler());
    

    step4 (MusicService)实现onBind()方法

       @Nullable
        @Override
        public IBinder onBind(Intent intent) {
    
            return mMessenger.getBinder();
        }
    
    

    step5 (MusicActivity) 创建一个ServiceConnection实例,在onServiceConnected方法中获取到service返回的messenger.

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

    step6 (MusicActivity)bindservice

            Intent intent = new Intent(this, MusicService.class);
            bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    

    step7 bind成功后,就可以获取到一个Messenger的实例,通过该实例activity可以向另外一个进程中的service发送message,例如:

    mNextBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mIndex = (mIndex+1)>=mMusicDatas.size()? 0 : mIndex+1;
                    setMusicNameAndSingerName(mIndex);
                    if(mMessenger != null) {
                        Message message = Message.obtain(null, 0);
                        message.arg1 = mIndex;
                        message.replyTo = mActivityMessenger;
                        try {
                            mMessenger.send(message);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
    

    至此,基于Messenger的由activity到service的进程间通信就是实现完成了.

    遇到的问题:

    当我试图Message实例的obj赋值为true时,会导致异常:

    java.lang.RuntimeException: Can't marshal non-Parcelable objects across processes.
    

    意思是说obj应该是一个实现了Parcelable接口的对象.

    解决方案:对于这种情况,应该使用bundle来传递数据.

    总结一下:
    1.activity与service以bind的方式通信.
    2.service中创建一个用于处理数据的handler,并以之为参数创建一个Messenger,通过onbind返回给activity.
    3.activity使用service返回的Messenger实例send message

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

  • 相关阅读:
    04_特征工程
    03_特征清洗
    02_数据探索
    01_简介
    cache是什么文件?
    gulp详细入门教程
    HTML5实战与剖析之触摸事件(touchstart、touchmove和touchend)
    h4和h5的区别
    弹性盒布局
    js面向对象
  • 原文地址:https://www.cnblogs.com/happyhacking/p/5318418.html
Copyright © 2020-2023  润新知