IBinder方法
如果你的服务只对你自己的应用程序使用,并且和客户端在同一个进程中运行(这种情况很常见),你应该通过扩展Binder类来创建你的接口并且从onBind()运行一个实例。客户端接收Binder并直接使用它来接入Binder实现,甚至Service中可用的公共方法。服务和客户端必须在同一个应用程序中的原因是客户端可以计算返回的对象并恰当的调用其APIs。服务和客户端也必须在同一个线程的原因是这种技术不能执行线程间操作。
Messager对比AIDL
当你需要执行IPC时,为你的接口使用一个Messenger比用AIDL实现简单,因为Messenger把所有对此服务的调用都排在一个消息队列中,而AIDL接口可能会不断的收到各客户端发送来的请求,这样就要求此服务具备处理多线程的(并发)能力。对于大多数应用程序,服务并不需要执行多线程,使用一个Messager允许服务在同一时间只处理一个调用(顺序的,非并发的处理消息)。如果处理多线程对你的服务很重要,那么,你应该使用AIDL来定义你的接口。
AIDL
只有您允许来自不同应用的客户端访问您的IPC服务并且您希望在服务中处理多线程,使用AIDL才是必要的。如果您不需要使用并发的IPC访问不同的应用,您应该通过继承Binder来创建您的接口,或者,如果您确实需要使用IPC,但是不需要处理多线程,那请继承Messenger来实现您的接口。总之,在实现一个AIDL之前,请确保您已经理解了Bound Services。
Before you begin designing your AIDL interface, be aware that calls to an AIDL interface are direct function calls. You should not make assumptions about the thread in which the call occurs. What happens is different depending on whether the call is from a thread in the local process or a remote process. Specifically:
- Calls made from the local process are executed in the same thread that is making the call. If this is your main UI thread, that thread continues to execute in the AIDL interface. If it is another thread, that is the one that executes your code in the service. Thus, if only local threads are accessing the service, you can completely control which threads are executing in it (but if that is the case, then you shouldn't be using AIDL at all, but should instead create the interface by implementing a Binder).
- Calls from a remote process are dispatched from a thread pool the platform maintains inside of your own process. You must be prepared for incoming calls from unknown threads, with multiple calls happening at the same time. In other words, an implementation of an AIDL interface must be completely thread-safe.
- The
oneway
keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from theBinder
thread pool as a normal remote call. Ifoneway
is used with a local call, there is no impact and the call is still synchronous.
- 注解:只有活动(activities),服务(services),和内容提供者(content providers)可以绑定到一个服务——你不能从一个广播接收器(broadcast receiver)绑定到一个服务。
所以,从你的客户端绑定到服务,你必须:
1.实现ServiceConnection。
-
你的实现必须复写两个回调方法:
-
-
当与服务的连接发生了不可预期的丢失,Android系统调用这个方法,例如,服务发生了冲突或被杀死。在服务被解绑时并不会调用这个方法。
-
当与服务的连接发生了不可预期的丢失,Android系统调用这个方法,例如,服务发生了冲突或被杀死。在服务被解绑时并不会调用这个方法。
2.调用bindService(),传递ServiceConnection的实现。
3.当系统调用onServiceConnected()回调方法时,你可以开始使用由接口定义的方法调用服务。
4.与服务解决连接,调用unbindService()。
- 当客户端被摧毁,它将会从服务解绑,但你应该始终在结果与服务的交互或当你的活动暂停时解绑,这样系统可以在不被使用时关闭。
-
-
管理绑定服务的生命周期-Managing the Lifecycle of a Bound Service
图1.服务的生命周期被启动,并允许绑定。当一个服务从所有客户端解绑,Android系统将将其摧毁(除非这个活动被onStartCommand()启动)。这样,如果你的服务只是纯粹一个绑定服务,那么你不需要自己管理其生命周期——Android系统将根据其是否被绑定到客户端,来管理其生命周期。
然而,如果你选择实现int, int) onStartCommand()回调方法,那么你必须明确的停止这个服务,因为服务现在被认为已被启动。在这种情况下,服务将一些运行,直到它被自身的stopSelf()方法停止,或其它活动组件调用stopService()方法,而不考虑其是否绑定到客户端。
此外,如果你的服务被启动,并接收绑定,那么当系统调用了onUnbind()方法,你可以有选择性的返回true,如果你希望下一次一个客户端绑定到服务时接收一个onRebind()方法调用(而不是接收一个onBind()调用)。onRebind()返回一个空值,但客户端依然可以接收到onServiceConnected()回调方法中的IBinder。图1展示了这种服务生命周期的逻辑。