Android进程间通信(二)- Messenger

2022-12-13 18:55:30 浏览数 (1)

概述

Messenger 翻译为信使,顾名思义,就是可以在不同进程之间传递Message对象。它是一种基于AIDL的轻量型的IPC方案。

定义

源码里面Messenger的定义比较简单,只是实现了Parcelable接口,之外提供了构造和发送方法。同时它也是一个final类。

代码语言:javascript复制
public final class Messenger implements Parcelable {
    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
    ...
    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }
}

从他的两个构造方法,其实可以看出有着AIDL的痕迹,比如“getIMessenger”、“IMessenger.Stub.”。所以可以看作是对AIDL的简单封装。

接着跟踪 getIMessenger(),发现

代码语言:javascript复制
   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);

        }
    }

可以看到getIMessenger方法返回的是MessengerImpl对象,而MessengerImpl是Handle的一个内部类,并且继承了IMessenger.Stub,实现了其send()方法。看到这,想必大家看出来了IMessenger.Stub这种形式就和AIDL使用方式很像,所以印证了之前的说法。Messenger的底层的确是AIDL。

MessengerImpl 类的实现可以看到,客户端msg通过binder方式传递过来,而当前进程的Handler将其加入自己的messagequeue并处理它。 PS: IMessenger类位于:

代码语言:javascript复制
frameworks/base/core/Java/android/os/IMessenger.aidl

使用

服务端

代码语言:javascript复制
public class ServerService extends Service {

    private static final String TAG = "ServerService";

    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }

    private final Messenger mMessenger = new Messenger(new MessengerHandler());

    private static class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what){
                case 1:
                    Log.i(TAG,"Message data = " msg.getData().getString("data"));
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
}

分3步:

  • 实现静态内部类继承Handler
  • 新建Messenger对象
  • Onbind方法返回Messenger.getBinder()

为了实现进程间通信,于是在Manifast文件注册可以指定进程号, 这样就实现了和主进程不同进程。

代码语言:javascript复制
        <service
            android:name=".ServerService"
            android:process=":remote"></service>

就这么简单。剩下的就是等着客户端来撩骚你了。

客户端

代码语言:javascript复制
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private Messenger mService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this, ServerService.class);
        bindService(intent,mConnect, Context.BIND_AUTO_CREATE);
    }

    private ServiceConnection mConnect = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG,"onServiceConnected  ");
            mService = new Messenger(service);
            Message mag = Message.obtain(null, 1);
            Bundle data = new Bundle();
            data.putString("data"," Hello , i come from client ");
            mag.setData(data);
            try {
                mService.send(mag);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
        }
    };

    @Override
    protected void onDestroy() {
        unbindService(mConnect);
        super.onDestroy();
    }
}

为了对称也分3步:

  • 绑定对应的service – bindService
  • 初始化ServiceConnection 对象
  • 拿到服务器返回的IBinder对象,通过这个初始化Messenger对象,就可以发送消息

运行结果

代码语言:javascript复制
xxxx.messagertest I/MainActivity: onServiceConnected  
xxxx.messagertest:remote I/ServerService: Message.what = Hello , i come from client

可以看到service收到了Activity的消息,并且service进程是xxxx.messagertest:remote,而Activity在xxxx.messagertest。说明进程间通讯成功实现!!

扩展双向通信

服务端

代码语言:javascript复制
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what){
                case 1:
                    Log.i(TAG,"Message.what = " msg.getData().getString("data"));
                    Messenger client = msg.replyTo; //主要添加这句
                    Message reply = Message.obtain(null ,2);
                    Bundle data = new Bundle();
                    data.putString("reply","ok , i get it!");
                    reply.setData(data); 
                    try {
                        client.send(reply);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }

客户端

代码语言:javascript复制
       @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG,"onServiceConnected  ");
            mService = new Messenger(service);
            Message mag = Message.obtain(null,1);
            Bundle data = new Bundle();
            data.putString("data","Hello , i come from client");
            mag.replyTo = mClientMessenger;  //这句需要添加
            mag.setData(data);
            try {
                mService.send(mag);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    ...
    private Messenger mClientMessenger = new Messenger(new ClientHander());

    private static class ClientHander extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 2:
                    Log.i(TAG,"Message.what = " msg.getData().getString("reply"));
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

总结一下,其实就是客户端需要指定Messenger的replyto,其他类似于之前的服务端实现。而服务器端只需要拿到replyTo对象就可以向客户端发送消息。

运行结果

代码语言:javascript复制
I/ServerService: Message.what = Hello , i come from client
I/MainActivity: Message.what = ok , i get it!

0 人点赞