博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
跨进程通信之Messenger
阅读量:6508 次
发布时间:2019-06-24

本文共 7130 字,大约阅读时间需要 23 分钟。

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文件中加入:

运行结果如下

 

 

 

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

转载地址:http://pndfo.baihongyu.com/

你可能感兴趣的文章
仿余额宝数字跳动效果 TextCounter
查看>>
你必须知道的.net学习总结
查看>>
Axure8.0 网页 or App 鼠标滚动效果
查看>>
大家好,新年快乐。
查看>>
mupdf不支持x64_Window权限维持(七):安全支持提供者
查看>>
labview如何弹出提示窗口_LabVIEW开发者必读的问答汇总,搞定疑难杂症全靠它了!...
查看>>
hikariconfig mysql_HikariConfig配置解析
查看>>
mysql批量数据多次查询数据库_mysql数据库批量操作
查看>>
jquery 乱码 传参_jquery获取URL中参数解决中文乱码问题的两种方法
查看>>
JDBC_MySQL_jdbc连接mysql_MySQL
查看>>
zcu106 固化_xilinx zcu106 vcu demo
查看>>
java ftpclient 代码_java后台代码ftpclient下载文件
查看>>
java数据库生成model_继承BaseModelGenerator 生成Model时添加数据库表字段 生成代码示例...
查看>>
smarty使用php代码,笑谈配置,使用Smarty技术_php
查看>>
silk v3 decoder php,解码转换QQ微信的SILK v3编码音频为MP3或其他格式
查看>>
linux不能访问80端口,lunux开放80端口(本地访问不了linux文件可能是这个原因)...
查看>>
android单位转换小程序,微信小程序中rpx与rem单位转换
查看>>
ps切图教程 android,PS前端切图完整教程
查看>>
HTML如何把输入框变成必填值,required输入框为必填项
查看>>
背锅侠逆袭之路
查看>>