Android开发艺术探索   第二章 下



Android IPC方式



这个单独做一节,因为这一节比较重要,从这节开始,技术细节会独立成另外Android的笔记,这边只记录大纲这样。



2.4  Android IPC方式



1.使用bundle(包含广播这个方式)

四大组件中,服务、活动、广播都是可以支持Intent中传递bundle数据的,bundle中传输的数据必须是可以序列化的,包括基本类型、实现了Serializable或parcellbale接口的对象,还有一些Android支持的特殊对象。需要留意的是,Bundle不支持的数据是无法通过它进行传输的,这是一种最简单的进程间通信方式。



2.文件共享


共享文件也是一个不错的方法,需要注意并发读写的问题,文件没有限制,容易出现同时操作导致出错,所以最好是用于交互不频繁的通信中。


SharePreferences是个特例,它底层实现是采用XML文件来存储键值对的,本质上来说,它也是属于文件存储中的一种,由于系统对它的读写有一定的缓存策略,缓存中也会有一份数据,所以多进程模式下系统对它的读写也是不可靠的。不建议在进程间通信使用。



3.使用Messenger(基于AIDL)


Messenger是一种轻量级的IPC方案,底层实现是AIDL。它对AIDL进行了封装,由于它一次处理一个请求,因此在服务端我们不用考虑线程同步的问题,因为不存在并发执行的情形。



服务端进程:需要创建一个Service处理服务端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder即可。



客户端进程:首先需要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建Messenger,通过这个Messenger就可以向服务端发送消息了,发送消息类型就是Message对象。如果需要服务端回应,客户端一样需要创建一个Handler并通过它来创建一个Messenger对象,并把这个Messenger对象通过Message的replyTo参数传个服务器,服务器可以通过replyTo参数回应客户端。



4.使用AIDL (基于Binder)


Messenger是串行处理客户端请求,如果有大量的并发请求,那么Messenger并不合适,这个时候需要我们自己来实现AIDL啦。



服务端:


需要创建一个Service处理服务端的连接请求,同时创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口即可。



客户端:


首先需要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象转成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。



是不是感觉听起来和Messenger很像,是的,他们流程都是AIDL,所有基本都是一样的。只不过Messenger是封装了Message这个消息对象类型,而我们自定义的AIDL可以自己写接口。


来看看AIDL支持的数据类型:基本数据类型,String和CharSequence,list只支持ArrayList,Map支持HashMap,Parcelable的对象,AIDL:所有的AIDL接口本身也可以在AIDL文件中使用。



5.使用ContentProvider (基于Binder)


内容提供者ContentProvider是系统专门提供不同应用进行数据共享的方式,需要注意的一些细节:CRUD操作、防止SQL注入和权限控制等。ContentProvider主要是以表格的形式来组织数据,虽然看起来很像数据库的样子,但其实具体实现没有要求,我们可以用SQLite数据库,也可以用文件,或者内存里面的对象。使用起来很简单,只需要继承ContentProvider,实现6个抽象方法就可以了:onCreate、query、updata、insert、delete、getType这六个。



6.使用Socket


首先你得知道,Socket熟称“套接字”,是网络通信中的概念,TCP/UDP这些底层都是基于Socke的,HTTP和HTTPS基于TCP的协议。TCP对应流式套接字,UPD对应用户数据报套接字。TCP提供稳定的双向通信功能,UDP提供不稳定的单向通信功能,UDP也可以实现双向通信,在性能上,UDP有更好的效率,缺点是不能保证数据能够正确传输。


使用Socket进行通信,需要网络权限,需要声明权限。其次,不能在主线程中访问网络,在4.0以上版本会抛出异常,因为进行网络访问很可能是耗时的,主线程不进行耗时操作。




2.5 BInder 连接池


在介绍AIDL连接池之前,先简单回顾下AIDL使用的大致流程:首先服务端创建一个Service和一个AIDL接口,然后创建一个类继承AIDL接口中的Stub中的抽象方法,在Service的onBind方法中返回这个类的对象,然后客户端就可以绑定服务端service,建立连接后就可以访问服务端的方法。


现在考虑一种情况:公司的项目越来越庞大了,现在有10个不同的业务模块都需要使用AIDL来进行进程间通信,那我们该怎么处理呢?也许你会说:“就按照AIDL的实现方式一个个来吧”,这是可以的,如果用这种方法,首先我们需要创建10个Service,这好像有点多啊!如果有100个地方需要用到AIDL呢,先创建100个Service?到这里,相信大家应该明白问题所在了。随着AIDL数量的增加,我们不能无限制地增加Service,Service是四大组件之一,本身就是一种系统资源。而且太多的Service会使得我们的应用看起来很重量级,因为正在运行的Service可以在应用详情页看到,当我们的应用详情显示有10个服务正在运行时,这看起来并不是什么好事。针对上述问题,我们需要减少Service的数量,将所有的AIDL放在同一个Service中去管理。在这种模式下,整个工作机制是这样的:每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同业务模块之间是不能有耦合的,所有实现细节我们要单独开来,然后向服务端提供自己的唯一标识和其对应的Binder对象;对于服务端来说,只需要一个Service就可以了,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来返回相应的Binder对象给它们,不同的业务模块拿到所需的Binder对象后就可以进行远程方法调用了。由此可见,Binder连接池的主要作用就是将每个业务模块的Binder请求统一转发到远程Service中去执行,从而避免了重复创建Service的过程。




2.6  选用适合的IPC方式



第二章到这了就结束了,这里做个总结,不动的应用场景对应不同方法,各自有各自的优劣。



Bundle


优点:简单易用


缺点:只能传输Bundle数据类型

适用场景:四大组件的进程间通信



文件共享


优点:简单易用


缺点:不适合高并发通信,不支持实时通信。


适用场景:无并发访问情形,交换简单的数据实时性不强的场景。



AIDL


优点:功能强大,支持一对多并发通信,支持实时通信。


缺点:使用复杂,需要处理线程同步


适用场景:一对多通信且有远程过程调用需求



Messenger


优点:功能一般,支持一对多串行通信,支持实时通信


缺点:不能处理高并发,不支持远程过程调用,只能传输Bundle数据类型


适用场景:低并发的一对多即时通讯,无远程过程调用需求,或者无须要返回结果的远程过程调用需求



ContentProvider


优点:数据源访问方面功能强大,支持一对多并发数据共享,可以扩展


缺点:受限的AIDL,主要提供数据源的增删查改操作


适用场景:一对多并发数据共享



Socket

优点:功能强大,支持一对多并发实时通信。


缺点:细节繁琐,不支持直接的远程过程调用


适用场景:网络数据交换

附上表格:

android 开发艺术探索 binder android开发艺术探索 第二版_读书笔记