前面我们介绍了 进程通信 AIDL 的学习和使用,这篇文章来介绍下 Android 中另一种 IPC 方式:Messenger。

Messenger“信使”,顾名思义,通过它可以在不同的进程中传递Message对象,在Message中放入我们要传递的内容,就可以实现进程间通信了。Messenger是一种轻量级的IPC 方案。

Messenger 有两个构造函数:

  • 以 Handler 为参数
  • 以 Binder 为参数
private final IMessenger mTarget;public Messenger(Handler target) {    mTarget = target.getIMessenger();}public Messenger(IBinder target) {    mTarget = IMessenger.Stub.asInterface(target);    //和前面的 AIDL 很相似吧}

不管是 IMessenger 还是 Stub.asInterface,这种使用方法都表明底层就是 AIDL
实现 Messenger 有如下步骤:

客户端进程:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private TextView receiveText;    private EditText input;    /**     * 客户端的 Messenger     */    private Messenger mClientMessenger = new Messenger(new Handler(){        @Override        public void handleMessage(Message msg) {            if (msg!=null && msg.arg1 == Constants.MSG_FROM_SERVER){                if (msg.getData() == null){                    return;                }                String content = (String) msg.getData().get(Constants.MSG_CONTENT);                receiveText.setText(content);            }        }    });    /** 服务端的 Messenger */    private Messenger mServerClient;    private ServiceConnection conn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            mServerClient = new Messenger(service);        }        @Override        public void onServiceDisconnected(ComponentName name) {            mServerClient = null;        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();        bindMessengerService();    }    private void bindMessengerService() {        /** 如下方式调用另外一个进程的 service ,但是这个service必须在当前工程清单文件中声明 */        Intent intent = new Intent(this,MessengerService.class);        bindService(intent,conn, Context.BIND_AUTO_CREATE);    }    private void initView(){        input = (EditText) findViewById(R.id.inputText);        Button sendBtn = (Button) findViewById(R.id.sendBtn);        receiveText = (TextView) findViewById(R.id.receiveText);        sendBtn.setOnClickListener(this);    }    @Override    public void onClick(View v) {        if (v.getId() == R.id.sendBtn){            String msgContent = input.getText().toString();            msgContent = TextUtils.isEmpty(msgContent) ? "默认消息" : msgContent;            Message message = Message.obtain();            message.arg1 = Constants.MSG_FROM_CLIENT;            Bundle bundle = new Bundle();            bundle.putString(Constants.MSG_CONTENT, msgContent);            message.setData(bundle);            message.replyTo = mClientMessenger;     //指定回信人是客户端定义的            try {                mServerClient.send(message);            } catch (RemoteException e) {                e.printStackTrace();            }        }    }}
  • 服务端的 Client,通过客户端的 ServiceConnection 绑定成功之后,通过new Messenger(service);传入service ,拿到客户端服务的对象 mServerClient

  • initView 中初始化界面,重要的就算点击按钮之后,通过服务端的 Messenger 发送消息这块了。

 Message message = Message.obtain(); message.arg1 = Constants.MSG_FROM_CLIENT;  // 设置标记 Bundle bundle = new Bundle();  bundle.putString(Constants.MSG_CONTENT, msgContent);  // 传递的消息内容 message.setData(bundle); message.replyTo = mClientMessenger;     //指定回信人是客户端定义的

最后通过mServerClient.send(message);将消息发送到服务端。

  • bindMessengerService()中请在工程中配置一下对应的 service

让这个 service运行在单独的进程中 。

服务端进程:

public class MessengerService extends Service {    private Messenger mMessenger = new Messenger(new Handler() {        @Override        public void handleMessage(final Message msg) {            if (msg != null && msg.arg1 == Constants.MSG_FROM_CLIENT) {                if (msg.getData() == null) {                    return;                }                String content = (String) msg.getData().get(Constants.MSG_CONTENT);  //接收客户端的消息                //回复消息给客户端                Message replyMsg = Message.obtain();                replyMsg.arg1 = Constants.MSG_FROM_SERVER;                Bundle bundle = new Bundle();                bundle.putString(Constants.MSG_CONTENT, "收到啦,你不就是说:"+content);                replyMsg.setData(bundle);                Messenger serverClient = msg.replyTo;                try {                    serverClient.send(replyMsg);     //回信                } catch (RemoteException e) {                    e.printStackTrace();                }            }        }    });    @Nullable    @Override    public IBinder onBind(Intent intent) {        return mMessenger.getBinder();    }}

可以看到Handler来处理客户端发送的消息,从消息中取出客户端的文本信息,而mMessenger 是一个 Messenger 的对象,它和handler关联起来,在onBind 方法中返回IBinder 对象,可以看到这里 是服务端来处理客户端的消息。代码比较简单易懂。

最后实现效果,app启动后 有两个进程,一个是 主工程4631 ,一个是 服务端4669

最后实现效果

当然我们可以把客户端和服务端和上次讲的 进程通信 AIDL 的学习和使用 一样,搞成两个app,这样的话看起来更加真实。
在客户端这里绑定的时候要使用

 private void bindMessengerService() {        Intent intent = new Intent();        //5.0 以后要求显式调用 Service,所以我们无法通过 action 或者 filter 的形式调用 Service        intent.setComponent(new ComponentName("com.zx.serviceclient","com.zx.serviceclient.MessengerService"));        bindService(intent,conn, Context.BIND_AUTO_CREATE);    }

把对应 com.zx.serviceclient下的服务进行绑定,指明绑定的具体服务所在包名和服务类名,同时需要在服务端的Module 中启动对应的service,并在清单文件中声明。这样就和上一篇文章中讲到的效果一样了,有两个app,客户端 和 服务端。

文章参考 :https://blog.csdn.net/u011240877/article/details/72836178

更多相关文章

  1. Android培训班(9)
  2. linux kernel suspend Resume
  3. Android(安卓)客户端与服务器端进行数据交互(二、登录客户端)
  4. Android(安卓)Says Bonjour
  5. Android开发指南-框架主题-基础知识
  6. Android(安卓)系统启动
  7. Android跨进程数据通讯-剪切板Clipboard
  8. Android开发中完全退出程序的三种方法
  9. [原]Android系统进程Zygote启动过程的源代码分析

随机推荐

  1. GoLang中协程图文详解
  2. 用Go语言编写一个简单的WebSocket推送服
  3. golang中gc实现原理介绍
  4. go语言的异常处理介绍
  5. golang操作Redis&Mysql&RabbitMQ的方法介
  6. go语言实现日志收集系统图文详解
  7. go的websocket实现(附代码)
  8. go语言time包的一些使用方法
  9. go语言中的并发介绍(附代码)
  10. Go中string转[]byte的陷阱