Android service通信

概要:介绍绑定服务端的三种方式:同一进程绑定服务、跨进程绑定服务(Messenger)、跨进程绑定服务(aidl)。 重点说一下通过Messenger、Service实现的进程间通信。

基础:AIDL(Android Interface Definition Language)——进程间通信的一种机制。它允许您定义客户端和服务端通过使用进程间通信(IPC)进行通信的编程接口。在Android上,一个进程无法正常访问另一个进程的内存。所以说,他们需要将他们的对象分解成操作系统能够理解的原语,并且把这些对象放在你的边界上。编写这些代码非常繁琐,所以Android使用AIDL来处理它。

使用场景:
在创建提供绑定的Service时,必须提供一个IBinder (客户端可以用来与服务进行交互的编程接口)。有三种方法可以定义接口:

1、扩展Binder类

如果您的Service对您自己的应用程序是私有的,并且与客户端在相同的进程中运行(这是常见的),则应该通过扩展Binder类并创建其实例,onBind()返回该实例。 客户端收到Binder,可以使用它直接访问Binder实现或甚至Service中可用的公共方法。

当您的服务只是您自己的应用程序的后台工作者时,这是首选技术。您不会以这种方式创建界面的唯一原因是因为您的服务被其他应用程序或单独的进程使用。

2、使用Messenger

如果您需要Service 和客户端位于不同的进程,则可以使用Messenger为服务创建一个interface。 以这种方式,服务定义响应不同类型的Message对象的Handler。 该Handler是Messenger的基础,可以与客户端共享IBinder,允许客户端使用Message对象向服务发送命令。 此外,客户端可以定义自己的Messenger,因此服务可以发回消息。

这是执行进程间通信(IPC)的最简单的方法,因为Messenger将所有请求排队到单个线程中,以便您不必将服务设计为线程安全。

3、使用AIDL

AIDL(Android Interface Definition Language)执行所有的工作,将对象分解为基元,操作系统可以在进程之间了解和编组它们以执行IPC。 之前使用的Messenger技术实际上是基于AIDL作为其底层结构。 如上所述,Messenger在单个线程中创建所有客户端请求的队列,因此服务一次接收一个请求。 但是,如果您希望您的服务同时处理多个请求,则可以直接使用AIDL。 在这种情况下,您的服务必须能够进行多线程并建立线程安全。

要直接使用AIDL,您必须创建一个定义编程接口的.aidl文件。 Android SDK工具使用此文件生成一个实现接口并处理IPC的抽象类,然后您可以在服务中扩展它。

注意:大多数应用程序不应该使用AIDL创建绑定的服务,因为它可能需要多线程功能,并可能导致更复杂的实现。因此,AIDL不适用于大多数应用程序。

异同:

  1. Messenger本质也是AIDL,只是进行了封装,开发的时候不用再写.aidl文件。

结合我自身的使用,因为不用去写.aidl文件,相比起来,Messenger使用起来十分简单。但前面也说了,Messenger本质上也是AIDL,故在底层进程间通信这一块,两者的效率应该是一样的。

  1. 在service端,Messenger处理client端的请求是单线程的,而AIDL是多线程的。

使用AIDL的时候,service端每收到一个client端的请求时,就会启动一个线程(非主线程)去执行相应的操作。而Messenger,service收到的请求是放在Handler的MessageQueue里面,Handler大家都用过,它需要绑定一个Thread,然后不断poll message执行相关操作,这个过程是同步执行的。

  1. client的方法,使用AIDL获取返回值是同步的,而Messenger是异步的。

Messenger只提供了一个方法进行进程间通信,就是send(Message msg)方法,发送的是一个Message,没有返回值,要拿到返回值,需要把client的Messenger作为msg.replyTo参数传递过去,service端处理完之后,在调用客户端的Messenger的send(Message msg)方法把返回值传递回client,这个过程是异步的,而AIDL你可以自己指定方法,指定返回值,它获取返回值是同步的。

其实,第二点是有办法解决的,在service端,Messenger的Handler可以只当作一个转发器,不处理请求,只转发请求到相应的处理线程(多是相应的HandlerThread),这样也可以达到异步的效果。

推荐阅读更多精彩内容