进阶式IPC机制

1.前言

  此文是在阅读<< Android开发艺术探索 >>的基础上进行总结记录.Android开发中有些场景需要开启多进程.就需要对多进程相关知识系统地了解.自己开车的Demo https://github.com/xwpeng/TestIPC

2.进程相关的adb命令

  adb shell ps 查看所有的进程
  adb shell ps pid 查看指定pid进程
  adb shell ps | grep 包名 指定包名查看进程信息
  adb shell cat /proc/pid/oom_adj 进程回收建议值

3.几种进程间通信的方式

  Android的IPC(Inter-Process Communication/进程间通信),可以使用Binder机制与Socket通信来实现,Bundle的Intent附带数据传递,ContentProvider自带实现了夸进程数据共享。
Android的ShareUID模式可以使两个具有相同shareUID并且签名相同的应用共享数据(data目录,组件信息,内存数据),他们看起来就像一个应用的两个部分。

4.多进程带来的问题

  系统在创建新的进程会分配独立的虚拟机,相当于启动一个应用,创建新的Application。
所以,不同进程会拥有独立的虚拟机,Application以及内存空间。一个应用的多进程模式可以理解为多个应用采用了ShareUID模式。
具体造成的影响:
1. 静态成员和单例模式完全失效。
2. 线程同步机制完全失效。
3. SharedPreferences不可靠.用ContentProvider包装过的SharePreferencesDPreference,多进程下可靠.
4. Application创建代码多次执行,每增一个进程,相当于启动一个应用,分配独立的虚拟机与内存。

5.开启多进程

  Android中只能通过给四大组件设置android:process来开启多线程,无法给一个实体类或者线程指定进程,代码运行在哪个线程,取决于调用代码的组件.
进程名以":"开头的为私有进程,其他为公有进程,公有进程可以使用ShareUID方式运行其他相同签名应用的组件(很少用).

6.序列化

  Intent与Binder传递数据需要先进行序列化.
  serializable是Java的序列化实现,用于对象与存储设备的读取保持,使用简单,大量I/O操作开销大.
serializable需要指定serialVersionUID,默认使用实体类的hash值.如果不指定serialVersion,当类进行改动,hash变化,就会造成反序列化失败,程序Crash.
  静态成员变量属于类不属于变量,不参与序列化.transient关键字标记的成员变量不参与序列化.
  Parcelable是android特有的,使用起来麻烦,主要是在内存序列化,效率高。

7.AIDL

  参考http://www.jianshu.com/p/c6a8e913efb3
  值得注意的是:客户端发请求调用transact方法,由服务端的onTransact来响应,
客户端发起远程请求的时候线程会挂起,等待服务端返回数据才继续执行,不会异步。
需要确定这个远程请求是否耗时,再决定是否再主线程做远程请求.
  如果你的aidl接口有引用到实体类,实体类要实现Parcelable,并且需要创建实体类xxx.aidl,引用实体的其他aidl文件需要import.添加实体类.aidl要注意路径必须与java目录下的路径完全一致.比如实体类Book是在./java/应用包名/entity/Book.java,在aidl下也得新建完全一直的目录结构./aidl/应用包名/entity/Book.aidl.见Demo:https://github.com/xwpeng/TestIPC User2.java
  如果客户端有多个同时操作服务端数据集合,服务端需要考虑线程同步.CopyOnWriteArray与ConcurrentHashMap支持自动的线程同步.服务端集合可以使用它们解决这个问题.
  AtomicBoolean,判断与set新值组装成原子操作,避免多线程并发问题.
  AIDL接口回调实现服务端调用客户端接口,比如有新消息来时推送.大家都知道,一个Activity实现某接口,将此接口传递到其他类中由其他类调用,这是面向接口编程.在AIDl中是怎么实现这中策略的呢.
1.客户端调服务端代码是定义一个AIDL接口,由服务端实现,然后在bind的回调中返回给客户端.如果在这个接口中定义方法能够将另一个AIDL接口A传给服务端,客户端实现A接口,那么服务端就能通过此接口方便的调用客户端接口.在Demo中IOnNewBookArrivedLIistener与NewBookReceiverActivity展示了这种用法.
2.服务端管理客服端接口要使用RemoteCallbackList,不然无法解绑客服端的推送.原因是:当客服端的书籍提醒接口实现实例通过AIDL接口方法传递到服务端会变成一个新的对象,用一般的List管理客服端接口在添加的时候添加的是新的对象(同一方法参数的新旧对象在AIDL中有一一对应的关系,这就是为什么服务端调用新对象的方法,客服端旧对象能够响应,猜测,TODO),解绑方法的参数,传递到服务端也是一个新的对象.这就造成接口管理List找不到注册时添加的接口,造成解绑失败.而RemoteCallbackLis是系统专门提供的用于跨进程listener的接口.工作原理是用一个Map结构存储接口.同一客户端跨进程传输参数服务端会产生新对象,但是它的底层Binder对象是不会变的,所以可以用它作为key来标识客户端,value则是客服端接口.且客服端挂了会自动移除相应键值对,自动支持线程同步.beginBroadCast和finishBroadCast必须配对使用.
3.如果服务端不使用RemoteCallBackList管理回调接口,发现先由MainActivity绑定PushService,再启动NewBookReceiverActivity的AIDL接口会被不断的回调,即使已经调用了Destroy().弄不明白为什么会这样,TODO.
  push进程挂掉监听.
  权限验证,在onTransact中调用,注意不要在onBind中判断权限.

8. Messenger

  Messager本质是对AIDL进行封装,由于时间问题,源码就不分析了.
  参考http://www.jianshu.com/p/253e424c377f
  梳理我demo的思路,程序设计首要是思路清晰.
Messenger通信
  这种方式是利用Handle消息队列互传消息,意味着这种方式是串行的.同时无法直接调用其他进程的方法,只能根据收到的消息来调用方法.返回值也只能用消息传递

9.in/out/inout参数标记探索

  参考你真的理解AIDL中的in,out,inout么?
  Book类的序列化需要添加

   protected Book(Parcel in) {
       readFromParcel(in);
    }

    public void readFromParcel(Parcel in) {
        id = in.readInt();
        name = in.readString();
        price = in.readDouble();
    }

  AIDL接口的java实现要调用才方法,没有将报错.见Demo:https://github.com/xwpeng/TestIPC Book.java
  总结:
  1.in表示服务端将接收传入的参数(Book book).服务端对接收到参数(book)做修改,客户端不会同步修改book;
  2.out表示服务端将不接收传入的参数(Book book),从源码看是新new了一个对象.服务端对接收到参数(book)做修改,客户端会同步修改book;
  3.inout表示服务端接收传入的参数(Book book.服务端对接收到参数(book)做修改,客户端会同步修改book.

10.TCP实现进程通信

/**
*
* * * * 见demo * * * *
*
**/

11.Binder管理(连接池?)

  我们希望在一个远程进程中处理很多不同的业务(实际场景没有遇到过),假设需要在远程进程中处理计算与安全中心业务。常规的做法是开2个service,这2个serivce跑在同一个进程中。现在想只用一个service就能处理很多不同的功能。
  声明IBinderPool.aidl,有方法Binder queryBinder(int code)。在连接完Service后,得到IBinderPool型的Binder对象,传入定义好的code调用此对象的queryBinder得到对应的业务aidl的Binder对象。
  用单例类将连接service,请求得到binder管理起来,完成一个实例一个连接能返回多个binder的目的。

IPC方式对比

f方式        优          缺         
Intent,Bundle    简单易用    单向,多用于四大组件传递初始数据,最多数据量1M 
文件交互             不支持多并发,操作麻烦,局限性大
Socket 功能强大,双向通信  实现与维护困难,多用于网络通信
ContentProvider        适用于数据提供,数据源共享,不适合数据交互与RPC(远程过程调用)
Messenger 实现简单   一对一还好,并发处理困难,RPC困难
AIDL 功能强大,拓展性强,支持多并发,需要处理好线程同步,支持RPC  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值