Android 多进程通信(2) - Binder、Messenger

在上篇文章《Android多进程通信概述》中,我们对Android中可用的多进程通信技术有一个总体的了解,知道多进程通信的重要性,本文就从最为常用也较为复杂的通信方式Binder开始,了解其机制及用法。

从Service说起

上篇文章提到,AIDL是Service跨进程通信的一种方式,因此也和Service有着不可分割的关系,Service中的 onBind() 方法可以使得Service与其他组件绑定和交互,该方法返回的 IBinder 对象定义了客户端用来与服务进行交互的编程接口,因此,创建提供绑定的服务时,必须提供 IBinder ,用以提供客户端用来和服务进行交互的编程接口。可以通过三种方式来定义接口:Binder,Messenger, AIDL。

扩展 Binder 类

若Service为只在本APP中使用,且与客户端运行在相同的进程下,则可以继承 Binder 类,使客户端通过该类访问服务端Service中的方法。具体步骤如下:

  1. 在Service中创建Binder扩展类的实例,该实例要满足下列其中一个条件:
    • 包含客户端可调用的public方法
    • 返回当前Service 实例,其中包含客户端可调用的public方法
    • 返回Service包含的其他类的实例,该实例包含客户端可调动的public方法
    IBinder localBinder = new LocalBinder();

    public class LocalBinder extends Binder {
        public LocalService getService() {
            return LocalService.this;
        }
    }
  1. 在Service的onBind() 回调方法返回这个Binder扩展类的实例
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return localBinder;
    }
  1. 在客户端中,从onServiceConnected() 回调方法中得到 Binder,并通过这个binder使用提供的方法绑定服务
    LocalService.LocalBinder binder;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder iBinder) {
            binder = (LocalService.LocalBinder) iBinder;
            LocalService localService = binder.getService();
            //得到Service实例localService,可以调用其中的方法
        }

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

要求服务和客户端必须在同一应用内,是为了便于客户端转换返回的对象和正确调用其 API。服务和客户端还必须在同一进程内,因为此方法不执行任何跨进程编组。

注:在OnBind()方法中需返回一个IBinder实例,不然onServiceConnected方法不会调用。

使用 Messenger

Messenger,信使,可以在不同的进程间传递message对象,在message中放入需要传递的数据就可以实现跨进程通信和传递数据。Messenger机制是基于消息的跨进程通信方式。 客户端和服务端可相互持有对方的Messenger来进行通信。

当需要进行进程间通信时,使用 Messenger 比使用 AIDL 更简单,因为 Messenger 会将所有Service调用排入队列,而 AIDL 会同时向 Service 发送多个请求,而Service则必须能够处理多线程。因此,Messenger适用于不需要处理多线程的Service,可以让 Service 一次处理一个调用。具体步骤如下:

  1. Service 实现一个 Handler,用来接收 client 每个调用的回调
   private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
           //handle message
        }
    }
  1. Service 端用Handler实例创建Messenger对象
Messenger messenger = new Messenger(new IncomingHandler());
  1. Service 端用 Messenger 创建一个 IBinder,并通过 onBind() 返回到客户端
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }
  1. Client 端用 IBinder实例化 Messenger(引用Service的Handler实例),并实例化Message发送给Service
    private Messenger messenger;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder iBinder) {
            messenger = new Messenger(iBinder);
            message = Message.obtain(null, MessengerService.MSG_ANSWER_NAME, 0, 0);
            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            messenger = null;
        }
    };
  1. Service 端接收到 Client 发送来的 Message,并在 Handler中接收每个Message进行处理
    private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_ANSWER_NAME:
                    //do something
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
Client与Server端通信

上述步骤可以实现将Server端对Client发送来的消息进行处理,但如果想让Clinet响应Service发送来的消息,也是可以实现的:在客户端实现一个Messenger,当客户端收到 onServiceConnected() 回调时,会向服务发送一条 Message,可以在该message中设置 replyTo 为客户端Messenger

客户端:

    private Messenger localMessenger = new Messenger(new LocalHandler());
    private Messenger messenger;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder iBinder) {
            messenger = new Messenger(iBinder);
            message = Message.obtain(null, MessengerService.MSG_ANSWER_NAME, 0, 0);
            message.replyTo = localMessenger;
            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

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

    class LocalHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            String result = msg.getData().getString("result");
            switch (msg.what) {
                case MessengerService.MSG_ANSWER_NAME:
                    //do something
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

服务端:

    private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_ANSWER_NAME:
                    //do something
                    Message newMsg = Message.obtain();
                    Bundle bundle = new Bundle();
                    newMsg.what = MSG_ANSWER_NAME;
                    bundle.putString("result", result);
                    newMsg.setData(bundle);
                    try {
                        msg.replyTo.send(newMsg);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
原理

而通过分析Messenger源码可以发现,其内部也是基于aidl文件的,具体分析由于篇幅限制就不再赘述了,其内部其实也是依赖一个aidl生成的类,这个aidl位于:frameworks/base/core/Java/android/os/IMessenger.aidl。也就是,我们代码中是:

Messenger mServiceMessenger = new Messenger(service);

而跟进去后会发现:

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

使用 AIDL

AIDL(Android 接口定义语言)执行将所有对象分解成原语的工作,操作系统可以识别这些原语并将它们编组到各进程中,以执行 IPC。之前采用 Messenger 的方法实际上是以 AIDL 作为其底层结构。Messenger 会在单一线程中创建包含所有客户端请求的队列,以便 Service 一次接收一个请求。 不过,若 Service 要同时处理多个请求,则可直接使用 AIDL,且服务必须具备多线程处理能力,并采用线程安全式设计。

如需直接使用 AIDL,需要创建一个定义编程接口的 .aidl 文件。Android SDK 工具利用该文件生成一个实现接口并处理 IPC 的抽象类,就可以在 Service 内对其进行扩展。

小结

关于 AIDL 的介绍会在单独一篇博文里讲解,且以上关于Binder和Messenger的相关内容都有实现,见github代码,且该代码需要切换分支查看,分支分别为 service-binderservice-messenger

你可能感兴趣的:(Android 多进程通信(2) - Binder、Messenger)