⾯试题之进程间通信问题
你在进程中通讯,使⽤什么? 出了AIDL外,还有其他的⽅式吗?
有⼤概四种⽅式:
⽅式⼀:访问其他应⽤程序的Activity
⽅式⼆:Content Provider
⽅式三:⼴播(Broadcast )
⽅式四:AIDL 服务
⽅式五:Messager
下⾯详细介绍⼀下Messager 进程间通信:
Messager 实现IPC 通信,底层也是使⽤了AIDL ⽅式。和AIDL ⽅式不同的是,Messager ⽅式是利⽤Handler 形式处理,因此,它是线程安全的,这也表⽰它不⽀持并发处理;⽽AIDL ⽅式是⾮线程安全的,⽀持并发处理,因此,我们使⽤AIDL ⽅式时需要保证代码的线程安全。⼤部分情况下,我们应⽤中不需
要并发处理。因此,我们通常只需要使⽤Messager ⽅式。
思想:在进程A 中创建⼀个Message ,将这个Message 对象通过IMessenger.send(message)⽅法传递到进程B (当然,Message 对象本⾝是⽆法被传递到进程B 的,send(message)⽅法会使⽤⼀个Parcel 对象对Message 对象编集,再将Parcel 对象传递到进程B 中,然后解编集,得到⼀个和进程A 中Message 对象内容⼀样的对象),再把Message 对象加⼊到进程B 的消息队列⾥,Handler 会去处理它。
先看下⾯这个例⼦
进程B 中代码
进程A 中代码 [java]
01. public  class  RemoteService extends  Service {  02.    public  static  final  int  GET_RESULT = 1;  03.    private  final  Messenger mMessenger = new  Messenger(new  Handler() {  04.        private  int  remoteInt = 1;//返回到进程A 的值  05.        @Override  06.        public  void  handleMessage(Message msg) {  07.            if  (msg.what == GET_RESULT) {  08.                try  {  09.                    plyTo.send(Message.obtain(null , GET_RESULT, remoteInt++, 0));  10.                } catch  (Remo
teException e) {  11.                        e.printStackTrace();  12.                }  13.            } else  {  14.                super .handleMessage(msg);  15.            }  16.        }  17.    });  18.      19.    @Override  20.    public  IBinder onBind(Intent intent) {  21.        return  Binder();  22.    }  23. }
上⾯这个例⼦很简单,⽬的就是从进程A 向进程B 的RemoteService 发⼀个消息,进程B 再把处理结果发给进程A 。
下⾯来深⼊分析⼀下Messenger 的实现过程
Messenger 类的⽅法:
public Messenger(Handler target) {
mTarget = IMessenger();
}
public IBinder getBinder() {
return mTarget.asBinder();
}
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
Handler 类的⽅法:[java]
01. private  Messenger mService;  02. private  boolean  isBinding = false ;  03. private  ServiceConnection mConnection = new  ServiceConnection() {  04.    @Override  05.    public  void  onServiceConnected(ComponentName name, IBinder service) {  06.        mService = new  Messenger(service);  07.        isBinding = true ;  08.    }  09.  10.    @Override  public  void  onServiceDisconnected(ComponentName name) {  11.        mService = null ;  12.        isBinding = false ;  13.    } };
02. ), mConnection, BIND_AUTO_CREATE);
[java]
01. //处理来⾃进程B 回复的消息  02. private  Messenger mMessenger = new  Messenger(new  Handler() {  03.    @Override  04.    public  void  handleMessage(Message msg) {  05.        if  (msg.what == RemoteServiceProxy.GET_RESULT) {  06.              Log.i("TAG", "Int form process B is "+msg.arg1);//msg.arg1就是remoteInt  07.        } else  {  08.              super .handleMessage(msg);  09.        }  10.    }  11. });进程通信方式
[java]
01. //向进程B 发⼀条消息,并接收来⾃进程B 回复过来的消息  02. Message message = Message.obtain(null , RemoteServiceProxy.GET_RESULT);  03. plyTo = mMessenger;  04. try  {  05.    mService.send(message);  06. } catch  (RemoteException e) {  07.        e.printStackTrace();  08. }
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
Handler.this.sendMessage(msg);
}
}
从上⾯代码可知,当进程A的Activity绑定进程B的RemoteService时,onBind⽅法返回⼀个MessengerI
mpl对象,它是IBinder类的⼦类。这个对象会被传递到进程A中,在进程A与进程B建⽴链接时,传到ServiceConnected(ComponentName name, IBinder service)⽅法中,IBinder service就是进程B返回的MessengerImpl对象。然后⽤service构建⼀个Messager对象
mService = new Messenger(service);
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
IMessenger.Stub.asInterface(target)⽅法会在进程A中创建⼀个IMessenger的代理类Proxy,看过AIDL的朋友会对这个很熟悉。
当使⽤mService发送⼀条消息时,实际调⽤的是代理类Proxy的send(Message msg)⽅法。
public void send(android.os.Message msg) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((msg!=null)) {
_data.writeInt(1);
msg.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
}
finally {
_le();
}
}
}
上⾯⽅法是将Message msg的内容写到Parcel _data对象中,然后调⽤进程B返回的MessengerImpl对象的transact⽅法。这个⽅法把_data 对象传递到进程B中,看下这个⽅法
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (Config.LOGV) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
在进程B中调⽤onTransact⽅法
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
........
case TRANSACTION_send:
{
android.os.Message _arg0;
if ((0!=adInt())) {
_arg0 = android.os.ateFromParcel(data);
}
else {
_arg0 = null;
}
this.send(_arg0);
return true;
}
.......
}
}
这个⽅法在进程B中恢复进程A传递过来的消息,然后调⽤this.send(_arg0);。再来看看send(_arg0)这个⽅法
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
Handler.this.sendMessage(msg);
}
}
把它加到进程B的消息队列中了,由Handler处理。Handler怎么处理这⾥就不再详解,不在本⽂范围内,这⼀块我之前研究过,下次有时间再写⼀篇Handler处理消息的⽂章

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。