Android进程间通信(IPC)之Messenger

来源:互联网 发布:数据录入平台 编辑:程序博客网 时间:2024/06/02 07:30

Messenger可以翻译成信使,当然翻译成啥玩意,顺你自己便吧!我们主要关心的是它的实现原理!
相信只要你理解了AIDL的进程间通信,对于Messenger来说这根本不是事,稍微研究一下它的实现,你会发现很好理解,他就是封装了IMessenger这个类,这个类是什么呀!要来是aidl文件生成的java来,就是通过IMessenger来进行进程间通信;那底层是通过什么传递?,不还是那个Binder!
先看一个例子:
服务端代码

public class MessengerService extends Service {    private static final String Tag = "MessengerService";    private Handler mServiceHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {            case 0x123:                String str = msg.getData().getString("str");                Log.e(Tag, str);                break;            default:                break;            }        }    };    private Messenger mServiceMessenger = new Messenger(mServiceHandler);    @Override    public IBinder onBind(Intent intent) {        return mServiceMessenger.getBinder();    }}

先创建了一个Handler对象,在创建了一个Messenger对象,通过Messager的getBinder返回一个Binder对象。
客户端代码

public class MainActivity extends Activity {    private Messenger mClientMessenger;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Intent i = new Intent(this, MessengerService.class);        bindService(i, mServiceConnection, BIND_AUTO_CREATE);    }    private ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceDisconnected(ComponentName name) {        }        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            if (service != null) {                mClientMessenger = new Messenger(service);                Message msg = Message.obtain();                msg.what = 0x123;                Bundle b = new Bundle();                b.putString("str", "美女,你好!");                msg.setData(b);                try {                    mClientMessenger.send(msg);                } catch (RemoteException e) {                    e.printStackTrace();                }            }        }    };}

启动服务成功后,接收到返回的Binder对象,然后创建一个Messenger对象。通过这个Messenger发送一句话 “美女,你好!”
最后在manifest中的服务中如下,让客户端和服务端跨进程;

         <service            android:name="com.messenger.use.MessengerService"            android:process=":remote" >        </service>

最后运行程序打印 如下:

首先我们首先看一下Messenger的构造方法:

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

第一个跟Handler有关,第二个跟IBinder有关;只看这个显然不是很清楚!我们先看第一个构造方法里面的mTarget = target.getIMessenger()是怎么回事;去到Handler类中去观察一下这个方法的实现

    final IMessenger getIMessenger() {        synchronized (mQueue) {            if (mMessenger != null) {                return mMessenger;            }            mMessenger = new MessengerImpl();            return mMessenger;        }    }

首先同步锁锁定Handler对象中关联的消息队列,判断成员mMessenger是否为null,非空直接返回,空的话,就重新new 一个对象返回;那么这个MessengerImpl是什么吗?看一下它的类就知道了

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

看到IMessenger.Stub会不会想到AIDL接口文件生成的java类,没想到的话,你再去了解一下AIDL是怎么回事!我们IMessenger.aidl这个aidl文件吧;这个文件对用户不可见,要去Android源码中去查看

package android.os;  import android.os.Message;  /** @hide */  oneway interface IMessenger {      void send(in Message msg);  }

它会生成IMessenger.java,Messenger就是通过它来进行进程间通信的;现在是不是很清晰了。
服务端上述程序代码中 private Messenger mServiceMessenger = new Messenger(mServiceHandler); 这句代码通过我们上面分析的时候会产生一个Binder ,当我们通过
mServiceMessenger.getBinder()方法的时候会返回这个Binder, 这是服务端的情况
下面看看客户端的情形 在onServiceConnected方法中,根据传递过来的Binder构造一个Messenger对象,再看看Messenger构造的内部;

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

当我们通过Messenger发送消息的时候,看看源码Messenger类中的代码

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

这个mTarget.send(message)会发起跨进程远程调用服务端!
我们再回到服务端,这时候服务端的Binder会调用自己的send方法,服务端的Binder是mServiceMessenger.getBinder()而来,在看看getBinder()方法源码

    public IBinder getBinder() {        return mTarget.asBinder();    }

这时mTarget.asBinder()返回的是本身mTarget。mTarget回去调用send方法,mTarget又是怎么来的
Mssenger的构造

     public Messenger(Handler target) {        mTarget = target.getIMessenger();    }

Handler类的中getIMessenger()方法,

final IMessenger getIMessenger() {        synchronized (mQueue) {            if (mMessenger != null) {                return mMessenger;            }            mMessenger = new MessengerImpl();            return mMessenger;        }    }

看了上面两个代码,是不是知道了 ,就是MessengerImpl 它是IMessenger.Stub的实现类;

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

当这个对象调用send方法的时候,你会发现,竟然把消息让Handler对象处理了,这个Handler对象就是我们构造的Handler对象。
饶了好多了,Messenger其实就是封装了Handler和IMessenger来进行跨进程通信,通信的本质还是要靠Binder!

0 0