Android跨进程通信之Messenger

借鉴自开发艺术


跨进程通信方式:

Intent附加extras

共享文件

Binder

ContentProvider

Socket


Bundle不支持的类型传不了。一种特殊场景:A进程正在进行一个计算,计算完后,需要发送给B,而且开启B的一个模块。但是结果的类型Bundle不支持。这个时候可以让A用Intent开启B的服务,让服务进行后台计算,计算完后再开启B中的某个模块,这样就用极小的代价满足了需求。


共享文件就是存储,读取一个文件。虽然不同的进程的资源不一样,但是外部的资源仍然是一样的。但是共享文件在Linux上是可以并发的,所以有可能出错。


Messenger

他可以在不同进程间传递Message对象,是一种轻量级的IPC,底层实现是AIDL。但是服务端不需要考虑同步问题,因为一次只会处理一个Message。

1.服务端进程

在服务端创建一个Service来处理客户端的连接请求,再创建一个Handler,通过这个Handler来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder即可。

2.客户端进程

客户端进程中,首先要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息了,发消息类型为Message对象。如果需要服务端能够回应客户端,就和服务端一样,我们还需要创建一个Handler并创建一个新的Messenger,并且把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。


一个通过Messenger发送消息的例子

public class MessageService extends Service {

    private static class MessengerHandler extends Handler {//Handler在这里是接收到消息后的回调
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 666:
                    Log.i("xbh", "消息是" + msg.getData().getString("msg"));
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    private final Messenger mMessenger = new Messenger(new MessengerHandler());//相当于给他一个回调

    public MessageService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();//从Messenger中获取binder并返回
    }
}

<service
    android:name=".MessageService"
    android:process=":hello" />

public class MessengerActivity extends AppCompatActivity {

    private Messenger mService;

    private ServiceConnection mConnection = new ServiceConnection() {//连接建立时的回调:发送信息
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService = new Messenger(service);
            Message msg = Message.obtain(null, 666);
            Bundle data = new Bundle();
            data.putString("msg", "hello, this is client");
            msg.setData(data);
            try {
                mService.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);
        Intent intent = new Intent(this, MessageService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

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

Message中的载体只有what,arg1,arg2,Bundle,replyTo。Message中的另一个字段object在同一个进程中是很实用的,但是在进程间通信的时候,也仅仅是系统提供的实现了Parcelable接口的对象才能通过它来传输。所以我们自定义的实现Parcelable接口的对象是不能通过object来传输的。


如果上面的例子想要实现服务端回应客户端的功能的话

服务端,修改MessageHandler

private static class MessengerHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 666:
                Log.i("xbh", "消息是" + msg.getData().getString("msg"));
                Messenger client = msg.replyTo;//msg中会维护之前那个Messenger,仍然是之前那个跨进程的消息队列
                Message replyMessage = Message.obtain(null, 888);
                Bundle bundle = new Bundle();
                bundle.putString("reply", "get it!");
                replyMessage.setData(bundle);
                try {
                    client.send(replyMessage);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
            default:
                super.handleMessage(msg);
        }
    }
}

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

客户端,新建一个Handler,在ServiceConnection中的回调中把这个回复的Handler交给msg的replyTo子段去维护

private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());

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

private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mService = new Messenger(service);
        Message msg = Message.obtain(null, 666);
        Bundle data = new Bundle();
        data.putString("msg", "hello, this is client");
        msg.setData(data);
        msg.replyTo = mGetReplyMessenger;//这句就是让他去维护
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};
其核心在于1.服务端可以拿到mGet...的实例。2.Activity第一个Messenger的参数是service,在这之后的Messenger都会先后接受到service是谁,发送者是谁,只不过这一切都是隐式的。(最后有个注意点,另外进程的log要切换到另外进程的log里去看)


流程




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值