Android 的 IPC 机制

IPC Inner-Process Communication 进程间通信

  1. 线程 线程是CPU调度的最小单元,同时线程是一种有限的系统资源
  2. 进程 进程指一个执行单元,PC 和 移动设备中指一个程序或者一个应用

process 开启多进程

  1. native 层也可以 fork 新的进程
  2. 有 : 以冒号简写和写完整进程名两种方式
  3. 以 :冒号方式,表明该进程是属于该应用的私有进程,其他应用组件不可以和他跑在同一个进程
  4. 不以 :冒号开头的进程属于全局进程,其他应用通过 ShareUID 方式可以和他跑在同一进程

adb 命令行查看

adb shell ps
adb shell ps | package name

多进程存在的问题

  1. 静态变量、单例模式完全失效
  2. 线程同步机制完全失效
  3. SharedPreferences 可靠性下降
  4. Application 会多次创建

IPC 方式

  1. Intent 传输
  2. 文件共享
  3. Messenger
  4. Soket
  5. AIDL
  6. ContentProvider

一、Inten

Intent 中的 Bundle 支持在不同进程间传递数据,启动另一进程 Service、Activity、BroadcastReceiver 时可以通过 Intent 传递数据

二、使用文件共享

  1. 共享文件也是一种方式,A 进程在文件中序列化进去一个对象,B 进程在文件中读取并恢复。
  2. 缺点:并发读写不可控
  3. 用于:是合租对数据同步要求不高的进程间进行通信,并妥善处理并发的读写问题
  4. SharedPreferences 同共享文件类似,不过对 SharedPreferences 的读写系统有一定的缓存机制,操作不当容易丢失数据,不建议在多进程通信中使用

三、Messenger

  1. 服务端:创建一个 Handler 对象,由 Handler 对象构造一个 Messager 对象 Messager msgr = new Messager(handler) ,在 onBind() 方法中返回由 Messager.getBinder() 得到的 Bindler 对象
  2. 客户端:onServiceConnected() 方法中,有 Binder 对象创建一个 Messenger 对象,通过 Messenger 对象的 send(Message msg) 方法将需要跨进程的数据发出
  3. 服务端:在 Handler 中根据 Msg 的 what 属性做出相应的处理
解析 Messager msgr = new Messager(handler); 方法
  1. 该构造方法内部,为 Messenger 的 IMessenger 对象初始化,其实是赋值了 Handler 的内部类 IMessenger.Stub 类的对象,IMessenger.Stub 类似于 Binder 解析过程中,自动生成的 AIDL 类中的 Stub 类,重写了 sendMessage 方法,Messager 的 send 方法是发送消息的,这里使用调用当前创建 Messenger 的 Handler 的 sendMessage 方法。Handler 发送的消息,最后的处理还是当前 Handler。

  2. Messenger 的 getBinder 方法返回了内部的 IMessenger 对象的 asBinder() 方法的返回值。类似于 Binder ,说明,IMessenger.Stub 是继承了 Binder 的。所以最后 Messenger 的 getBinder 方法的到的就是 AIDL 过程中,那个 Stub 类的实现类对象。对了,没毛病

  3. 将 IMessenger.Stub 这个 Binder 类传递到客户端,客户端会调用 Messenger mesger = new Messenger(IBinder binder) 方法得到 Messenger 对象,可以清晰的看的,类似 AIDL 客户端的处理过程,客户端根据 IBinder 对象得到了 Messenger 类型的对象。

    public Messenger(IBinder target) {
    mTarget = IMessenger.Stub.asInterface(target);
    }

  4. 客户端通过 IMessenger.Stub 的 send 方法跨进程发送消息,其实是调用了在服务端中的 Handler 发送消息的方法。只不过在发送消息的时候 IMessenger.Stub 的 send 方法是会将需要传递的参数先序列化,传递到服务端后反序列化,再由反序列化得到的数据让服务端的 Messenger 对象来处理,即调用 Handler 的发送方法,最后处理任务在 服务端,直到结束。

    Messager:

    public Messenger(Handler target) {
    mTarget = target.getIMessenger();
    }

    Handler:

    final IMessenger getIMessenger() {
    synchronized (mQueue) {
    if (mMessenger != null) {
    return mMessenger;
    }
    mMessenger = new MessengerImpl();
    return mMessenger;
    }
    }

    MessageImpl:

    private final class MessengerImpl extends IMessenger.Stub {
    public void send(Message msg) {
    msg.sendingUid = Binder.getCallingUid();
    Handler.this.sendMessage(msg);
    }
    }

  5. 如果客户端需要在发出消息之后还能收到服务端的消息,就需要客户端在绑定成功后也创建自己的 Handler 对象创建 Messenger 对象,并通过 send 方法中的 Messge 对象的 replyTo 参数将 Messenger 穿递到服务端,服务端通过 Message 的 replyTo 参数也会得到 Messenger 对象。也就可以通过客户端传来的 Messenger 对象来向客户端发送消息了。

  6. Message 的 replay 参数类型是一个 Messenger ,可以使用 Messege 来携带 Messenger 对象。

  7. Messenger 的 getMessenger(Handler h) 方法封装了 AIDL 中 IBinder b = new IMessenger.Stub 过程

  8. Messenger 的 getMessenger(IBinder binder) 方法封装了 Messenger msger = IMessenger.Stub.asInterface(IBinder b) 过程

  9. Messenger 一次处理一个请求,所以也不用考虑线程同步的问题,因为使用的是 Handler 处理数据, 消息队列中的消息是串行执行的。

Binder 连接池

  1. 使用 BinderPool 绑定 Service ,
  2. 创建 不同的 AIDL ,生成器实现类
  3. 创建 IBinderPool 的 AIDL 接口,定义根据 CODE 获取 IBinder 的方法
  4. 创建 Service ,onBind 方法中返回 IBinderPool 类型的 IBinder
  5. 客户端中得到 IBinderPool 对应的 IBinder 对象
  6. 客户端中由 IBinder 对象的 query 方法传入 CODE 调用服务端的 服务,返回需要的 IBinder
  7. 客户端根据 IBinder 再调用服务端相应服务
    注意:bindService 的过程必须结束之后才可以使用得到的 IBinder 对象进行操作,否则会空指针

  8. 客户端每次请求的时候需要两步,第一步要先绑定 Service 获取 IBinderPool 的 IBinder

  9. 第二部,由 IBinder 转化为 IBinderPool 类型
  10. 第三部,进行操作

  11. Binder 连接池的作用为,将以上两部进行封装,在 BinderPool 初始化的时候就完成与Service 的绑定也就是得到 IBinder 对象

  12. 客户端直接使用该 IBinder 对象的 query 方法就可以得到想要的 Binder
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值