本文主要是介绍进程间通信 Messenger,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
使用Messenger进行通信的方式要比aidl写起来方便的多,这种方式大概的流程为:
这种方式可以做到双向通信
那么下面就是代码了,首先是服务端:我自己的测试的项目在另一台电脑上,所以就拿借鉴的博主的代码来了,其实
我自己写的是差不多的
- package com.example.aidlClientdemo;
- import android.app.Service;
- import android.content.Intent;
- import android.os.Handler;
- import android.os.HandlerThread;
- import android.os.IBinder;
- import android.os.Message;
- import android.os.Messenger;
- import android.os.RemoteException;
- public class ProcessCommonicationService extends Service{
- private static final int MSG_SUM = 0x110;
- HandlerThread handlerThread = new HandlerThread("myHandlerThread");
- //这里在handler构造器内传入handlerThread的Lopper,可以让handleMessage在handlerThread的线程内队列执行
- private Messenger mMessenger = new Messenger(new Handler(handlerThread.getLooper())
- {
- @Override
- public void handleMessage(Message msgfromClient)
- {
- Message msgToClient = Message.obtain(msgfromClient);//返回给客户端的消息
- switch (msgfromClient.what)
- {
- //msg 客户端传来的消息
- case MSG_SUM:
- msgToClient.what = MSG_SUM;
- try
- {
- //模拟耗时
- Thread.sleep(2000);
- msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2;
- msgfromClient.replyTo.send(msgToClient);
- } catch (InterruptedException e)
- {
- e.printStackTrace();
- } catch (RemoteException e)
- {
- e.printStackTrace();
- }
- break;
- }
- super.handleMessage(msgfromClient);
- }
- });
- @Override
- public void onCreate() {
- super.onCreate();
- //使用handlerThread可以进行队列执行
- handlerThread.start();
- }
- @Override
- public IBinder onBind(Intent intent)
- {
- return mMessenger.getBinder();
- }
- }
客户端代码结束之后就是服务端的代码
- package com.imooc.messenger_client;
- import android.content.ComponentName;
- import android.content.Context;
- import android.content.Intent;
- import android.content.ServiceConnection;
- 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.v7.app.AppCompatActivity;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.LinearLayout;
- import android.widget.TextView;
- public class MainActivity extends AppCompatActivity
- {
- private static final String TAG = "MainActivity";
- private static final int MSG_SUM = 0x110;
- private Button mBtnAdd;
- private LinearLayout mLyContainer;
- //显示连接状态
- private TextView mTvState;
- private Messenger mService;
- private boolean isConn;
- private Messenger mMessenger = new Messenger(new Handler()
- {
- @Override
- public void handleMessage(Message msgFromServer)
- {
- switch (msgFromServer.what)
- {
- case MSG_SUM:
- TextView tv = (TextView) mLyContainer.findViewById(msgFromServer.arg1);
- tv.setText(tv.getText() + "=>" + msgFromServer.arg2);
- break;
- }
- super.handleMessage(msgFromServer);
- }
- });
- private ServiceConnection mConn = new ServiceConnection()
- {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service)
- {
- mService = new Messenger(service);
- isConn = true;
- mTvState.setText("connected!");
- }
- @Override
- public void onServiceDisconnected(ComponentName name)
- {
- mService = null;
- isConn = false;
- mTvState.setText("disconnected!");
- }
- };
- private int mA;
- @Override
- protected void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //开始绑定服务
- bindServiceInvoked();
- mTvState = (TextView) findViewById(R.id.id_tv_callback);
- mBtnAdd = (Button) findViewById(R.id.id_btn_add);
- mLyContainer = (LinearLayout) findViewById(R.id.id_ll_container);
- mBtnAdd.setOnClickListener(new View.OnClickListener()
- {
- @Override
- public void onClick(View v)
- {
- try
- {
- int a = mA++;
- int b = (int) (Math.random() * 100);
- //创建一个tv,添加到LinearLayout中
- TextView tv = new TextView(MainActivity.this);
- tv.setText(a + " + " + b + " = caculating ...");
- tv.setId(a);
- mLyContainer.addView(tv);
- Message msgFromClient = Message.obtain(null, MSG_SUM, a, b);
- msgFromClient.replyTo = mMessenger;
- if (isConn)
- {
- //往服务端发送消息
- mService.send(msgFromClient);
- }
- } catch (RemoteException e)
- {
- e.printStackTrace();
- }
- }
- });
- }
- private void bindServiceInvoked()
- {
- Intent intent = new Intent();
- intent.setAction("com.zhy.aidl.calc");
- bindService(intent, mConn, Context.BIND_AUTO_CREATE);
- Log.e(TAG, "bindService invoked !");
- }
- @Override
- protected void onDestroy()
- {
- super.onDestroy();
- unbindService(mConn);
- }
- }
在上面的例子中,是传递了基本类型的参数,而我们实际使用中则很多都会需要用到传递自定义类型,这种时候只需要这么做就行了
- Message msgFromClient = Message.obtain(null, MSG_SUM, a, b);
- msgFromClient.replyTo = mMessenger;
- Bundle bundle = new Bundle();
- bundle.putParcelable("data", new User());
- msgFromClient.setData(bundle);
- if (isConn)
- {
- //往服务端发送消息
- mService.send(msgFromClient);
- }
通过上面的方式可以方便的进行进程间的通讯
那么,为什么通过这种方式可以进行进程间通讯呢?这一点在我解读的文章中也有描述
之前我了解过aidl的进程通讯方式,在aidl的通讯方式可以发现与这里非常相似
1、bindService的方式
2、ServiceConnection的使用
3、aidl接口的对象获取,其实可以发现这里也是一样的
这里调用的通讯方式为Messenger mService = new Messenger(service);
而aidl的接口对象获取方式为:ICalcAIDL mCalcAidl = ICalcAIDL.Stub.asInterface(service);
表面上看起来好像有点不同,但是,如果我们去看Messenger的构造器
- public Messenger(IBinder target) {
- mTarget = IMessenger.Stub.asInterface(target);
- }
这里返回的mTarget对象为
private final IMessenger mTarget;
跟aidl客户端的方式一模一样,在调用通讯方法send(Message message)我们再去看
- public void send(Message message) throws RemoteException {
- mTarget.send(message);
- }
那么客户端我们发现了是一样的,再去看服务端呢?
在服务端我们的代码是
- private Messenger mMessenger = new Messenger(new Handler(handlerThread.getLooper())
- {
- @Override
- public void handleMessage(Message msgfromClient)
- {
- Message msgToClient = Message.obtain(msgfromClient);//返回给客户端的消息
- switch (msgfromClient.what)
- {
- //msg 客户端传来的消息
- case MSG_SUM:
- msgToClient.what = MSG_SUM;
- try
- {
- //模拟耗时
- Thread.sleep(2000);
- msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2;
- msgfromClient.replyTo.send(msgToClient);
- } catch (InterruptedException e)
- {
- e.printStackTrace();
- } catch (RemoteException e)
- {
- e.printStackTrace();
- }
- break;
- }
- super.handleMessage(msgfromClient);
- }
- });
- @Override
- public IBinder onBind(Intent intent)
- {
- return mMessenger.getBinder();
- }
而aidl的通讯方式是
- private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub()
- {
- @Override
- public int add(int x, int y) throws RemoteException
- {
- return x + y;
- }
- @Override
- public int min(int x, int y) throws RemoteException
- {
- return x - y;
- }
- };
然后
- public IBinder onBind(Intent t)
- {
- Log.e(TAG, "onBind");
- return mBinder;
- }
那么,现在的Messenger方式又是怎样的呢
我们首先来看Messenger的构造器,来看看这这里面做了什么
- public Messenger(Handler target) {
- mTarget = target.getIMessenger();
- }
这个IMessenger,其实是依赖一个aidl生成的类
于:frameworks/base/core/java/android/os/IMessenger.aidl
.
- package android.os;
- import android.os.Message;
- /** @hide */
- oneway interface IMessenger {
- void send(in Message msg);
- }
这样,在服务端就只差一个东西了,就是实现了 IMessenger.Stub的对象,这个对象我们去哪里找?
然后我们去看
- public Messenger(Handler target) {
- mTarget = target.getIMessenger();
- }
这里的target.getMessenger()方法,我们进去看一下,可以看到
- 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) {
- msg.sendingUid = Binder.getCallingUid();
- Handler.this.sendMessage(msg);
- }
- }
这样一来,需要的要素就都齐了,按照现在的代码来推测的话,不难推测出
- @Override
- public IBinder onBind(Intent intent)
- {
- return mMessenger.getBinder();
- }
- public IBinder getBinder() {
- return mTarget.asBinder();
- }
这里调用了asBinder()方法,再进去看
- @Override public android.os.IBinder asBinder()
- {
- return this;
- }
这里这个asBinder方法的源码是aidl文件在gen路径下生成的类里面可以看到的,如果读者想看的话,可以在aidl的例子中查看,就可以看到
那么Messenger配合Handler的进程间通信的原理到这里就分析结束了,从这个看来的话,其实我们完全也可以自己写一个类似于Messenger的对象用来进行进程间通信,并且利用Message可以传递数据的特性来进行数据的传递,可以说还是非常方便的
这篇关于进程间通信 Messenger的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!