• Android开发——进程间通信之Messenger


    0.  前言

    不论是Android还是其他操作系统,都会有自己的IPC机制,所谓IPCInter-Process Communication)即进程间通信。首先线程和进程是很不同的概念,线程是CPU调用的最小单元,进程一般在PC和移动设备上指一个程序或者一个应用,一个进程可以包含多个线程。

    IPC方式有很多,在Android中常用的IPC方式包括Bundle、文件、MessengerAIDLContentProviderSocket等方式。

    本篇主要讲解使用Messenger的方式。本文原创,转载请注明出处为SEU_Calvin的博客

     

    1.  Messenger

    Messenger是系统为我们封装好的一套IPC方案,它的底层是基于AIDLHandler。使用Messenger可以在不同进程中传递Message对象,并在Message中放入我们需要传递的数据,就可以实现数据的进程间通信了。

    Messenger的构造方法如下所示:

    public Messenger(Handler target) {
         mTarget = target.getIMessenger();
    }
    
    public Messenger(IBinder target) {
         mTarget = IMessenger.Stub.asInterface(target);
    }

    既然是进程间通信吗,那么直接看代码好了,先看服务器端所在进程的代码:

    public class MessengerService extends Service {
        private static final String Messenger_TAG = "Messenger";
        private static class ServerMessengerHandler extends Handler {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 0:
                        // 接收到客户端的信息
                        Log.i(Messenger_TAG, msg.getData().getString("client-data") + " " + Thread.currentThread().toString());
                        // 返回信息给客户端
                        Messenger replyMessenger = msg.replyTo;
                        Message message = Message.obtain();
                        message.what = 1;
                        Bundle data = new Bundle();
                        data.putString("server-data", "hello client, I have received your message! ");
                        message.setData(data);
                        try {
                            replyMessenger.send(message);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    default:
                        super.handleMessage(msg);
                }
            }
        }
    
        // 服务端Messenger
        private Messenger serverMessenger = new Messenger(new ServerMessengerHandler());
    
        @Override
        public IBinder onBind(Intent intent) {
            return serverMessenger.getBinder();
        }
    }
    

    服务器端创建一个Service来处理客户端的连接请求,同时创建一个Handler并以此为参数实例一个Messenger来接收客户端Messenger发来的message,最后在onBind方法返回这个MessengerBinder。在handleMessage()中不仅展示了客户端传来的信息,还使用Messenger replyMessenger =msg.replyTo获取客户端Messenger对象,装载数据后通过replyMessenger.send(message)返回message信息给客户端。完成了回复的功能。最后看一个客户端的代码:

    public class MainActivity extends AppCompatActivity {
        private static final String Messenger_TAG = "Messenger";
        private Messenger clientMessenger;
        private Button button;
        // 接收服务端返回信息的Messenger
        private Messenger replyMessenger = new Messenger(new ClientMessengerHandler());
        private static class ClientMessengerHandler extends Handler {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 1:
                        // 接收到服务端返回的信息
                        Log.i(Messenger_TAG, msg.getData().getString("server-data") + " " + Thread.currentThread().toString());
                        break;
                    default:
                        super.handleMessage(msg);
                }
            }
        }
    
        private ServiceConnection serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                clientMessenger = new Messenger(service);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            button = (Button) findViewById(R.id.messenger);
    
            // bind服务端Service
            Intent intent = new Intent(this, MessengerService.class);
            bindService(intent, serviceConnection, BIND_AUTO_CREATE);
    
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 发送消息到服务端
                    Message message = Message.obtain();
                    message.what = 0;
                    Bundle data = new Bundle();
                    data.putString("client-data", "hello server");
                    message.setData(data);
    
                    // 指定接收服务端返回信息的Messenger
                    message.replyTo = replyMessenger;
    
                    try {
                        clientMessenger.send(message);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            });
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unbindService(serviceConnection);
        }
    }
    

    首先在onCreate()中使用bindService()绑定服务,绑定成功后回调onServiceConnected()并在其中获得服务器返回的Binder对象,并通过这个Binder对象创建出Messenger对象clientMessenger。这里需要注意的是,与服务的连接意外中断时(例如当服务崩溃或被终止时)会回调onServiceDisconnected()方法。而当客户端主动取消绑定时,则不会调用该方法

    点击按钮后clientMessenger.send(message)向服务器端发送消息,注意这里message消息通过replyTo生成了replyMessenger实例,即接收服务端返回信息的Messenger,并在其构造参数中自定义了接收并处理服务端返回信息的Handler

    点击按钮后结果如下,在两个进程中分别打印出信息:

     



    这样整个客户端和服务端的跨进程通信过程就使用Messenger完成了。参考源码点击下载

    Messenger 会在单一线程中创建包含所有客户端请求的队列,如果你想让服务同时处理多个请求,则可直接使用 AIDL。在此情况下,你的服务必须具备多线程处理能力,并采用线程安全式设计

    因此AIDL和经过封装的Messenger相比,最大的不同就是AIDL具备多线程处理能力,下一篇将介绍使用AIDL进行进程间通信的介绍。

  • 相关阅读:
    系统开发——页面跳转函数的书写
    PC 端自动化最佳方案
    access 点滴
    调用outlook发邮件
    mac安装vmware fusion后设置vmnet8上网
    Gin框架国内安装教程
    mac下一些vscode的初始化设置和使用
    Mac: 使用SDK切换gradle版本
    transfer.sh -- 使用 curl 从命令行上传文件并返回下载地址的文件分享服务(可自架服务端)
    使用ffmpeg转码,解决IDM从youtube下下来的视频在机顶盒上放不出声音问题(使用GPU加速)
  • 原文地址:https://www.cnblogs.com/qitian1/p/6461447.html
Copyright © 2020-2023  润新知