Android-AIDL,service,Binder,Bundles,Messenger,transact()与onTransact()函数

很多的Service就是通过Binder机制来和客户端通讯交互的。明白Binder的话,在很大程度上就能理解程序运行的流程。

》Service就是提供服务的代码,这些代码最终体现为一个个的接口函数,所以,Service就是实现一组函数的对象,通常也称为组件。Android 的Service 有以下一些特点:

  1. 请求Service服务的代码(Client)  和 Service本身(Server) 不在一个线程,很多情况下不在一个进程内。跨进程的服务称为远端(Remote)服务,跨进程的调用称为IPC。通常应用程序通过代理(Proxy)对象来访问远端的Service。
  2. Service 可以运行在native 端(C/C++),也可以运行在Java 端。同样,Proxy 可以从native 端访问Java Service, 也可以从Java端访问native service, 也就是说,service的访问与语言无关。
  3. Android里大部分的跨进程的IPC都是基于Binder实现。
  4. Proxy 通过 Interface 类定义的接口访问Server端代码。
  5. Service可以分为匿名和具名Service. 前者没有注册到ServiceManager, 应用无法通过名字获取到访问该服务的Proxy对象。
  6. Service通常在后台线程执行(相对于前台的Activity), 但Service不等同于Thread,Service可以运行在多个Thread上,一般这些Thread称为 Binder Thread.
Binder全貌

Native 实现:  IBinder,  BBinder, BpBinder, IPCThread, ProcessState, IInterface, etc

Java 实现:  IBinder, Binder, BinderProxy, Stub, Proxy.

Binder Driver: binder_proc, binder_thread, binder_node, etc.

    Android 系统中 Service 信息都是先 add ServiceManager 中,由 ServiceManager 来集中管理,这样就可以查询当前系统有哪些服务。而且 ,Android 系统中某个服务例如 MediaPlayerService 的客户端想要和 MediaPlayerService 通讯的话,必须先向 ServiceManager 查询 MediaPlayerService 的信息,然后通过 ServiceManager 返回的东西再来和 MediaPlayerService 交互。

> 所谓的service有Local Service和Remote Service区分:

LocalService:就是client和Service在同一个进程当中。

RemoteService:就是client 和Service在不同的进程中。

绑定一个运行的Service

  可以创建一个即是运行的又是绑定的service,也就是通过startService()来让这个Service运行,然后client通过bindService()来绑定到Service。那么当service启动后,系统不会在所有客户端解除绑定unBindService()后销毁service,而是,你必须通过调用stopSelf()stopService()显示地停止这个service。

根据Android的设计,即使同一个Activity都不一定运行在同一个进程中,所以就要进程间传递数据了,

Parcel对象的使用

  Android 中的Parcel是一个容器,主要作用于存储序列化数据,然后通过Binder在进程间传递这些数据。Parcel可以包含原始数据类型(用各种对应的方法写入,比如writeInt(),writeFloat()等),可以包含Parcelable对象,它还包含了一个活动的IBinder对象的引用,这个引用导致另一端接收到一个指向这个IBinder的代理IBinder。

  注:Parcel不是一般目的的序列化机制。这个类被设计用于高性能的IPC传输。因此不适合把Parcel写入永久化存储中,因为Parcel中的数据类型的实现的改变会导致旧版的数据不可读。

》 Bundles类

  Bundles是一种类型安全的Map容器,可用于存储任何不同类型的数据。它具有很多对讀写数据的性能优化,并且它的类型安全机制避免了当把它的数据封送到Parcel中时由于类型错误引起的BUG的调试的麻烦,可以使用的方法为: writeBundle(Bundle), readBundle(), and readBundle(ClassLoader)。

活动对象

  Parcel的一个非同寻常的特性是读写活对象的能力。对于活动对象,它们的内容实际上并没有写入,而是仅写入了一个令牌来引用这个对象。当从Parcel中读取这个对象时,你不会获取一个新的对象实例,而是直接得到那个写入的对象。有两种活动对象可操作:

Binder对象

  它是Android跨进程通讯的基础。这种对象可被写入Parcel,并在读取时你将得到原始的对象或一个代理对象(可以想象:在进程内时得到原始的对象,在进程间时得到代理对象)。可以使用的方法们是: writeStrongBinder(IBinder), writeStrongInterface(IInterface), readStrongBinder(), writeBinderArray(IBinder[]), readBinderArray(IBinder[]), createBinderArray(), writeBinderList(List), readBinderList(List), createBinderArrayList()。

FileDescriptor对象

  它代表了原始的Linux文件描述符,它可以被写入Parcel并在读取时返回一个ParcelFileDescriptor对象用于操作原始的文件描述符。ParcelFileDescriptor是原始描述符的一个复制:对象和fd不同,但是都操作于同一文件流,使用同一个文件位置指针,等等。可以使用的方法是:writeFileDescriptor(FileDescriptor), readFileDescriptor()。

无类型容器类

  一类final方法,用于读写标准的java容器类。这些方法们是:writeArray(Object[]), readArray(ClassLoader), writeList(List), readList(List, ClassLoader), readArrayList(ClassLoader), writeMap(Map), readMap(Map, ClassLoader), writeSparseArray(SparseArray), readSparseArray(ClassLoader)。

  IBinder

Android的远程调用就是通过IBinder来实现的,远程调用的基本接口,还可以用于进程内调用,该接口定义了与远程对象交互的协议,不可以直接实现这个接口,要派生实现。

   主要API:

transact():向远端的IBinder对象发送发出调用。onTransact():是远程的对象能够响应另一端发送过来的调用请求。这两个API都是同步执行的。transact()方法要一直阻塞到onTransact()方法调用完成后才返回。

transact()发送的数据类型是Pracel类型的数据,是一种一般的缓冲区,除了有数据外还有一些描述他内容的元数据。元数据用于管理IBinder对象的引用,这样就能在缓冲区从一个进程移动到另一个进程时保存这些引用(对象句柄)。这样就保证了当一个IBinder被写入到Parcel并发送到另一个进程中,如果另一个进程把同一个IBinder的引用回发到原来的进程,那么这个原来的进程就能接收到发出的那个IBinder的引用。这种机制使IBinder和Binder像唯一标志符那样在进程间管理。

    系统为每个进程维护一个存放交互线程的线程池。这些交互线程用于派送所有从另外进程发来的IPC调用。例如:当一个IPC从进程A发到进程B,A中那个发出调用的线程(这个应该不在线程池中)就阻塞在transact()中了。进程B中的交互线程池中的一个线程接收了这个调用,它调用Binder.onTransact(),完成后用一个Parcel来做为结果返回。然后进程A中的那个等待的线程在收到返回的Parcel后得以继续执行。实际上,另一个进程看起来就像是当前进程的一个线程,但不是当前进程创建的。

   Binder机制还支持进程间的递归调用。例如,进程A执行自己的IBinder的transact()调用进程B的Binder,而进程B在其Binder.onTransact()中又用transact()向进程A发起调用,那么进程A在等待它发出的调用返回的同时,还会用Binder.onTransact()响应进程B的transact()。总之Binder造成的结果就是让我们感觉到跨进程的调用与进程内的调用没什么区别。

    当操作远程对象时,你经常需要查看它们是否有效,有三种方法可以使用: 
1 transact()方法将在IBinder所在的进程不存在时抛出RemoteException异常。 
2 如果目标进程不存在,那么调用pingBinder()时返回false。 
3 可以用linkToDeath()方法向IBinder注册一个IBinder.DeathRecipient,在IBinder代表的进程退出时被调用。

  用法:

要实现IBinder来支持远程调用,应从Binder类派生一个类。Binder实现了IBinder接口。但是一般不需要直接实现此类,而是跟据你的需要由开发包中的工具生成,这个工具叫aidl。你通过aidl语言定义远程对象的方法,然后用aidl工具生成Binder的派生类,然后就可使用之。当然,你也可以直接从Binder类派生以实现自定义的RPC调用,或只是实例化一个原始的Binder对象直接作为进程间共享的令牌来使用。

     AIDL(Android接口定义语言)执行把对象分解为操作系统能够理解并能跨进程封送的基本体以执行IPC 的所有的工作。 在Android中这里的AIDL就是通信的载体,而 Stub类就是将这个载体解析成通信双方都能读懂的数据格式的一个功能类。 所以也就解释了为什么在自己实现aidl文件的时候一定要继承自AIDL自动生成的实现类的内部类Stub类了。

如果知道RPC的分布式编程知识就能很好的理解为什么要定义一个特殊的接口,实现的时候要继承自Stub类了。
Messenger实现远程进程通信:
使用方法:
  • service实现一个接收从客户端的每个调用引起的回调的Handler

  • Handler被用来创建一个Messenger对象(它是Handler的一个引用)

  • Messenger创建一个从serviceonBind()返回给客户端的IBinder

  • 客户端使用IBinder来实例化这个Messenger(它引用到serviceHandler),客户端用它来service发送Message

  • Service在它的Handler中接收每个消息—具体的,是在handleMessage()方法中.

     

这此方式下,service中没有能让客户端调用的方法,客户端传送的是service在它的Handler中接收的"消息"(Message对象)

   应用组件(客户端)可以调用bindService()绑定到一个serviceAndroid系统之后调用serviceonBind()方法,它返回一个用来与service交互的IBinder

绑定是异步的.bindService()会立即返回,它不会返回IBinder给客户端.要接收IBinder,客户端必须创建一个ServiceConnection的实例并传给bindService()ServiceConnection包含一个回调方法,系统调用这个方法来传递要返回的IBinder

注:只有activities,services,contentproviders可以绑定到一个service—你不能从一个broadcastreceiver绑定到service


你可能感兴趣的:(Android,编程)