开发者社区> 科技小能手> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

跨进程通信之Messenger

简介:
+关注继续查看

1.简介

Messenger,顾名思义即为信使,通过它可以在不同进程中传递Message对象,通过在Message中放入我们需要的入局,就可以轻松实现数据的跨进程传递了。Messenger是一种轻量级的IPC方案,其底层实现是AIDL。

Messenger的使用方法很简单,它对AIDL进程了封装,并且由于它一次只处理一个请求,因此在服务端我们不需要考虑同步的问题。

 

2.实现跨进程通信

1)服务端进程

首先我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象。然后在Service的onBind方法中返回这Messenger对象底层的Binder即可。

2)客户端进程

客户端进程中,首先需要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建一个Messenger,并通过这个Messenger对象向服务端发送Message。此外,如果需要服务端响应客户端,我们就需要像服务端那样创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务器,服务器就可以通过这个replyTo参数回应客户端了。

 

     Messenger由于是在AIDL上进行了封装,其使用过程相对比较简单,下面的示例实现了客户端发送消息给服务端,服务端会根据客户端发送的消息予以回复并将回复的结果显示在客户端上。

3)下面直接贴上client和service的代码,最后附上运行结果。

Client:package com.pignet.messengerdemo2;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends AppCompatActivity {    private  static  TextView tvMsgFromService;
    Button btnSend;
    EditText etClient;    private Messenger mService;    private Messenger mGetReplyFromService =new Messenger(new MessengerHandler());    private static class MessengerHandler extends Handler{
        @Override        public void handleMessage(Message msg) {            switch (msg.what){                case 1:
                    tvMsgFromService.setText(msg.getData().getString("reply"));                    break;


            }            super.handleMessage(msg);
        }
    }    private ServiceConnection mConnection = new ServiceConnection() {
        @Override        public void onServiceConnected(ComponentName name, IBinder service) {
            mService=new Messenger(service);
        }

        @Override        public void onServiceDisconnected(ComponentName name) {


        }
    };

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnSend= (Button) findViewById(R.id.btn_send);
        etClient= (EditText) findViewById(R.id.et_client);
        tvMsgFromService = (TextView) findViewById(R.id.tv_msg_from_service);
        Intent intent= new Intent(MainActivity.this,MessengerService.class);
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE);

        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View v) {
                String msgFromClient;
                Message msg = Message.obtain(null,0);
                Bundle data = new Bundle();                if((msgFromClient=String.valueOf(etClient.getText()))==null){
                    Toast.makeText(MainActivity.this,"The Message is null",Toast.LENGTH_SHORT).show();
                }else{
                    data.putString("msg", msgFromClient);
                    msg.setData(data);
                    msg.replyTo= mGetReplyFromService;                    try {
                        mService.send(msg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }

            }
        });


    }

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

 

Service:

package com.pignet.messengerdemo2;import android.app.Service;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.support.annotation.Nullable;import android.util.Log;/**
 * Created by DB on 2017/7/2. */public class MessengerService extends Service {    private static final String TAG="MessengerService";    private static  class  MessengerHandler extends Handler{
        @Override        public void handleMessage(Message msg) {            switch (msg.what){                case 0:
                    Log.i(TAG, "receive msg from client: "+msg.getData().getString("msg"));
                    Messenger mService = msg.replyTo;
                    Message replyMessage = Message.obtain(null,1);
                    Bundle bundle = new Bundle();
                    bundle.putString("reply","您的信息"+msg.getData().getString("msg")+"已收到,稍后会有回复");
                    replyMessage.setData(bundle);                    try{
                        mService.send(replyMessage);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
            }            super.handleMessage(msg);
        }
    }    private final Messenger mMessenger = new Messenger(new MessengerHandler());
    @Nullable
    @Override    public IBinder onBind(Intent intent) {        return mMessenger.getBinder();
    }
}

 

 

这里为了模拟不同应用间的跨进程通信,将Service类运行在了与Client不同的进程中,这样就可以实现和不同应用间通信一样的效果。

所以我们需要在manifests文件中加入:

<service android:name=".MessengerService"
    android:process=":romote"></service>

运行结果如下

 

 

 

3.Messenger源码浅析:

     进入到Messenger源码后,查看它的结构

Messenger类有两个构造函数,分别是可以用Handler和IBinder实现,这也是我们之前实现跨进程中通信中实例化Messenger类中已经用到的两种构造函数。

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

因为之前提到过Messenger的底层实现是AIDL,所以这边我看这个IMessage和那个IBookManager有的类似,点开后发现确实如此

public interface IMessenger extends android.os.IInterface {    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements
            android.os.IMessenger {        private static final java.lang.String DESCRIPTOR = "android.os.IMessenger";        public Stub() {            this.attachInterface(this, DESCRIPTOR);
        }        public static android.os.IMessenger asInterface(...}        public android.os.IBinder asBinder() {            return this;
        }

        @Override        public boolean onTransact(int code, android.os.Parcel data,
                android.os.Parcel reply, int flags)                throws android.os.RemoteException {...}        private static class Proxy implements android.os.IMessenger {...}    public void send(android.os.Message msg)            throws android.os.RemoteException;
}

之前我们为BookManager类定义的方法是一个addBook和getBookList,而这边我们发现Messenger对AIDL的封装中加入的是一个send方法。

那这个方法是在哪里实现的呢。

private final class MessengerImpl extends IMessenger.Stub {        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

它是在Handler类中的MessengerImpl方法中得到实现的,这也就可以解释我们发送的message可以在Handler的handleMessage中出现了。

最后我们再回到Messenger类中看看Messenger的另一个重要方法:

    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

这里我们就可以串联起来了,Messenger类通过传入Handler或是IBinder来获得IMessenger的实例,然后调用send方法实际是在远程调用IMessenger的send方法。

这里我们就差不多把Messenger的机制理清了。

最后附上刚才实现的例子的一个简图:

 


本文转自lzwxx 51CTO博客,原文链接:http://blog.51cto.com/13064681/1944370

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
跨区域网络的通信学习静态路由
跨区域网络的通信学习静态路由
72 0
线程之间的通信(二)
线程之间的通信(二)
28 0
线程间通信
  如果一个多线程程序中每个线程处理的资源没有交集,没有依赖关系那么这是一个完美的处理状态。你不用去考虑临界区域(critical section),不用担心存在所谓的条件竞争(race condition),当然也不用去单行执行顺序,当然这种状态只是完美情况下,事实往往没有这么完美。
769 0
进程间通信
在用户应用程序在经常用到C库的进程间通信函数,实际上,这些进程间通信函数在内核中是通过系统调用好文件系统的机制实现的。 1 管道 管道是只用于连接读进程和写进程,以实现它们之间通信的共享文件。因而它又称共享文件。
834 0
进程通信
  进程间通信就是在不同进程之间传播或交换信息,进程间控制信息的交换称为低级通信,进程间大批量数据的交换称为高级通信。 进程通信分为3种: 1.共享存储器系统:为了传送大量数据,在存储器中划出一块共享存储区,诸进程可通过对共享存储区进行读数据或写数据以实现通信。
659 0
线程间通信(转)
  我们看下面的图 图1     我们来看线程间通信的原理:线程(Thread B)和线程(Thread A)通信, 首先线程A 必须实现同步上下文对象(Synchronization Context), 线程B通过调用线程A的同步上下文对象来访问线程A,所有实现都是在同步上下文中完成的.
555 0
23703
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载