闭门造车姚师傅

Android IPC之 Service和Messenger

字数统计: 1.6k阅读时长: 6 min
2017/03/12 Share

IPC机制是Android的重要组成部分,本文介绍其中的Service和Messenger。结合模拟的支付调用作为例子,翔实明了,简直不能再良心。

IPC(进程间通信)

Interprocess Communication

Service

A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.

可以看到主要有两点是比较有特点的:不可见并且和用户长时间交互、为其他应用程序提供服务。

Service可以脱离Activity的生命周期独立存在。不过,有一点看上去Service要比Thread“弱”一些:Service一般是不会在新的线程中运行,如果里面进行了耗时操作的话,还是需要新开线程的。

Service主要分为应用程序内部使用的Local Service 和 进行IPC的Remote Messenger Service(含AIDL)。

作用

  • A facility for the application to tell the system about something it wants to be doing in the background (even when the user is not directly interacting with the application). This corresponds to calls to Context.startService(), which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it.

    应用程序告诉操作系统要在后台处理些事情。

  • A facility for an application to expose some of its functionality to other applications. This corresponds to calls to Context.bindService(), which allows a long-standing connection to be made to the service in order to interact with it.

    向其他应用程序暴露自己的一些功能,即跨进程通信。

Service的启动

1
bindService(Intent service, ServiceConnection conn, int flags);
  • service,要绑定的那个Service

  • coon,这个接口有两个方法,对应service的bind和unbind两个节点。bindService是异步的,onServiceConnected() 作为绑定成功的回调。

  • flag,设置绑定的模式,如BIND_AUTO_CREATE

    bindService()会立即返回空值,ServiceonBinder()返回Binder时回调ServiceConnection的onServiceConnected()方法,并将该Binder作为参数传入。

1
startService(Intent service)

使用 bindService()启动Service,在Service失去所有绑定后将执行onDestroy()

只要使用了startService()方法(执行onCreate的调用或者在bind之后的调用),Service不会在Activity退出后stop。

Lifecycle of Service

IBinder/Binder

远程对象的基本接口,为进行高性能的进程内/间调用而设计的轻量级远程调用机制的核心部分。这个接口描述了与远程对象进行交互的抽象协议。一般使用的时候从Binder继承,不要直接implement这个接口。

1
IBinder onBind();

真正的通信部分由Binder完成。API文档中有更具体的描述

一般来说,对于一个仅仅在应用程序内部使用的Service我们可以拓展Binder,添加getService()这个方法,来达到暴露Service内部功能的目的。但是对于进程间的调用来说这样就很难行得通了(本地没有对应的class文件,不知道Service里面到底添加了哪些方法),所以,自上而下,来看Messenger。

Messenger

这个类的注释文档中写道:

Reference to a Handler, which others can use to send messages to it. This allows for the implementation of message-based communication across processes, by creating a Messenger pointing to a Handler in one process, and handing that Messenger to another process.

Note: the implementation underneath is just a simple wrapper around a {@link Binder} that is used to perform the communication.

引用,指向一个Handler。可以被用来发送消息(充当信使/邮差的功能)。通过在一个进程创造一个指向Handler的Messenger并且把这个Messenger传递到另一个进程,来允许基于Message的进程间通信。

注意:这个类的底层是对Binder的一个简单封装,Binder是用来执行通信的。(这个类的结构很简单,里面封装了一些Binder的行为)

虽然把这些名称翻译成中文挺奇怪的,但是找到这些类在现实生活中的映射对于更好的理解有很大帮助。Messenger,译作“信使”,应该是古代负责传递消息的使节或衙役之类的人物。在IPC机制中起到的作用就应该是传递信息,比如Service持有一个Messenger,通过这个Messenger发送消息。

Constructor

1
new Messenger(IBinder/Handler target); //IBinder-Client / Handler-Service

构造方法可以接收两种参数,也分别对应了两种情形:

  • IBinder

    在绑定Activity的时候,bindService()要求一个参数ServiceConnection,而绑定成功的回调结果就是一个Binder(由Service的onBind()返回)。

    这个构造方法一般是用在请求绑定的一端,构造出来的Messenger向Service发送Message

  • Handler

    Handler作为Android里的跨线程机制的重要组成部分,和Message一直有着密不可分的关系。它的作用就是handle一些东西(Message),而在Service的使用中,一般是由请求端向Service端发出一个请求(信息包含在Message里)。这也就意味着,在引入Messenger的情况下,Service中要包含一个Handler用来处理发过来的请求。

    这个构造方法一般用在Service端,将Handler和Messenger链接起来。

以上两个构造方法完成了Messenger的传递。


具体过程

Messenger的主要作用过程如下:

  1. Messenger在Service中以Handler以参数创建

    1
    Messenger mMessenger = new Messenger(new PaymentHandler()); //Simple Sample
  2. Service被绑定后,发起绑定的一方用Binder为参数创建。

    Service中返回Messenger的Binder:

    1
    2
    3
    4
    5
    @Override
    public IBinder onBind(Intent intent) {
    Log.i(TAG, "onBind");
    return mMessenger.getBinder();
    }

    Activity(eg.)中获取并实例化:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ServiceConnection conn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    //来自Service的Messenger
    Messenger messenger = new Messenger(service);
    ......
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    ......
    }
    };
  3. 进行通信:

    1
    2
    3
    Message msg = Message.obtain();
    //fill your info into msg
    messenger.send(msg);

实现双向的消息发送

在ServiceConnection的onServiceConnected()里面发送一个Message,具体过程如下:

  • new 一个Handler,负责处理Service发过来的消息
  • 用这个Handler创建一个Messenger
  • 发送一个Message,replyTo设置为刚才创建的Messenger

一个实例:

​ 模拟一个支付调用,简单得有些简陋。

​ 一侧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@SuppressLint("HandlerLeak")
Handler responseHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//打印支付结果
Log.i(TAG, "handleMessage: Response from Service");
Log.i(TAG, "handleMessage: " + msg.obj);
}
};
msg.replyTo = new Messenger(responseHandler);
//发起支付请求
msg.obj = "I request to pay $233.33.";
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}

​ 另一侧:

1
2
3
4
5
6
7
8
9
10
11
12
public void handleMessage(Message msg) {
//打印支付的消息内容
Log.i(TAG, "handleMessage: " + msg.obj);
try {
//模拟支付成功的回调
Message reply = Message.obtain();
reply.obj = "Payment Success!";
msg.replyTo.send(reply);
} catch (RemoteException e) {
e.printStackTrace();
}
}

打印出来的Log如下:

1
2
3
4
5
6
I/IPC:LocalService: onCreate
I/IPC:LocalService: Received start id 1: Intent { cmp=com.boileryao.ipc/.LocalService }
I/IPC:LocalService: onBind
I/IPC:LocalService: handleMessage: I request to pay $233.33.
I/ContentValues: handleMessage: Response from Service
I/ContentValues: handleMessage: Payment Success!

Happy Coding :)

via 锅炉工

ref:

Android Developer :: Service

CATALOG
  1. 1. Service
    1. 1.0.1. 作用
    2. 1.0.2. Service的启动
    3. 1.0.3. IBinder/Binder
  • 2. Messenger
    1. 2.0.1. Constructor
    2. 2.0.2. 具体过程
    3. 2.0.3. 实现双向的消息发送