Android中的IPC机制

什么是IPC

IPC是跨进程通信的简称,全称太长了,不想写了。由于Android中分为了UI线程和其他线程,而且对UI的操作只能在UI线程,为了防止卡顿,我们需要把一些操作放到其他线程处理。那么处理完毕之后如何通知UI线程做出处理呢?这就要靠IPC机制了。
当然,IPC不止在Android中有运用,很多地方也有使用。

Android中的多进程模式

开启多进程模式很简单,只需要在menifest文件中添加android:process属性即可,具体情况网上有很多例子,不再赘述。
但是开启了多进程之后,很多单进程时的问题就浮现了出来,比如,数据共享的时候同步会出问题,作者对这些情况做了总结,大致有如下几种
1.静态成员和单例模式失效
2.线程同步机制失效
3.SharedPreferences的可靠性下降
4.Application会多次创建

Android中的序列化

在进入IPC的总结之前,先来总结一个必不可少的东西,序列化,我们熟悉的是继承Serializable接口,来实现对象的可序列化过程,这种方式很简单,基本不用做多余操作,最多设置一下ID以反序列化之后的比较之用。
Android也提供了一套序列化机制——Parcelable接口,要实现这个接口就需要复杂一些的方法,需要实现几个必备的方法,也很简单,不详细说明。

两种序列化机制的区别

那么,这两种机制有何不同呢?首先,Serializable接口的序列化方式是java提供的,开销比较大,但是胜在简单。
而Parcelable的序列化方式开销比较小,但是使用起来稍显复杂,在应用内部的情况下,应该优先选择使用。
如果是在网络传输的过程中,建议使用Serializable方式,首先是简单,其次是不会因为Android系统的版本而造成差异。

Binder概括

首先,Binder是Android中的一个类,实现了IBinder接口,是链接各种manager和managerservice的桥梁,是客户端与服务端通信的桥梁。
那么,Binder到底是如何运作的呢?我们来看一个书上的例子,一个系统生成的AIDL文件的结构

这个例子是一个手动实现的Binder,整个文件看起来非常的长而无须,我们不妨跟随作者的脚步一点点来分析它
第一部分,这是一个叫BookManagerImpl的类,继承了Binder并实现了IBookManager接口
第二部分,其内部有一个内部类,private static class Proxy implements IBookManager同样也实现了IBookManager接口

BookManagerImpl的各个方法

1.public static IBookManager asInterface(IBinder obj) 用于转化服务端的Binder对象为客户端的AIDL接口,区分进程,如果是跨进程,返回的是proxy对象,否则的话返回stud对象本身
2.public IBinder asBinder() 返回当前的Binder对象
3.public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 运行在Binder线程池中,根据code和参数来执行不同的方法,参数从data中获取,然后把结果写入reply中,如果返回false,客户端的请求会失败。
4.public List<Book> getBookList() 与 public void addBook(Book book) throws RemoteException 实现了IBookManager接口中的方法

内部类Proxy的各个方法

大致与BookManagerImpl相同,不过内部的getBook和addBook是通过RPC来实现的,这些方法都运行在客户端,当进行RPC时会被挂起,所以不能在主线程操作,当RPC结束时,会读取结果并写入。

到了这里,Binder的工作流程就大概介绍完了,是不是看起来很复杂,仔细分析起来却很简单呢,有了Binder,我们就可以继续分析接下来的形形色色的IPC方式了。

Android中的几种IPC机制概览

首先说一下Android中的几种常见的IPC机制,Binder是android自己独特的一套机制,在系统层级经常被用到,很多IPC方式都会用到它,上面已经做过了介绍。
android中IPC的方式大概有以下几种
1.使用Bundle 最常见的IPC方式,在多个场合都被使用
2.文件共享 通过对一个文件的读写来进行通信的方式
3.使用Messager 相信大家都很熟悉,messager和handler的组合使用来进行IPC
4.使用AIDL android为我们提供的一种Binder的简化使用方式,实现容易
5.ContentProvider 是Android中专门用于对外部提供数据访问的方式,也是唯一方式,例如读取联系人
6.使用Socket 把跨进程通信当做网络通信来处理,也可以实现IPC的效果

由于1,2,6的方式很简单也很常见,这里就不详细描述了,下面来重点总结一下3,4,5的Android中独特的IPC方式

Messager方式的IPC

顾名思义,使用Message对象来进行IPC,其底层是一个AIDL,这是对其的封装,每次只会处理一条Messager消息,所以不存在并发的问题

服务端

创建一个Service,同时创建一个Handler并通过它创建一个Messager对象,并在onbind将其的binder返回即可

客户端

使用bindService绑定服务,并在ServiceConnection对象的哦你ServiceConnected方法中把返回的IBinder对象转化为Messager对象,在建立Message对象,加入数据,通过Messager对象的send方法进行发送

如果要服务端接收到消息后有回复的话,通过msg的replyTo来获取一个Messager对象,然后和客户端发送的过程是一样的
而客户端,需要一个接受消息的Messager和Handler,还需要在发消息给服务端的时候把服务端接收回复的Messager通过Message的replyTo发回去,这样服务端才能拿到它,进行收到消息之后的回复。

AIDL方式的IPC

服务端

首先定义AIDL文件,其实就是一些特殊格式的接口,不过参数有所限制,需要是可序列化对象或者几个限定的类型之一
其次,实现远程服务端的Service,主要是实现系统生成的XXXManager.stub()内部类中的AIDL接口中对应的方法

其他杂项

RemoteCallbackList类,可以实现跨进程删除添加listener,对于做观察者模式开发有帮助,不过使用方式比较特殊,在使用前必须beginBroadcast使用后需要finishBroadcast。
耗时方法不要在UI线程调用
还需要注意断开连接之后的重连
以及访问的权限认证,可以在onbind方法或者ontransact方法中进行。

客户端

使用bindService绑定服务,并设定绑定成功后的ServicConnection类,将返回的Service转换为AIDL类型,然后就可以调用其中的方法了·

ContentProvider方式的IPC

该方式底层依然是使用的Binder,不过经过系统的封装,更加简单易用

创建FfR

使用非常简单,新建一个类,继承ContentProvider类并实现其必须实现的几个方法即可,具体的内部实现可以自己定义
在menifest文件中申明为provider,并添加android:authorities属性,android:permission属性即可

使用

通过getContentResolver.methodname(params)来调用即可,当然,如果需要对应权限,要申请,methodname对应于几个已经实现的方法,参数表中比较重要的一个是uri,对应android:authorities的值

不同IPC方式的比较

Bundle 简单易用,但是只能传输支持的数据类型,可以用于四大组件之间传输数据
文件共享 简单易用,但是不适合高并发,适用无并发,实时性不高的场景
AIDL 功能强大,支持一对多并发,有些复杂,需要处理好线程同步,用于一对多有远程过程调用的情况
Messager 功能一般,但是不能处理高并发,不支持RPC,只能传输Bundle支持的类型,用于底并发情况,无RPC情况
ContentProvider 数据源访问方面强大,支持一对多并发,可以实现自定义操作,主要提供CRUD操作,用于一对多的进程间数据共享
Socket 功能强大,支持一对多实时通信,不支持直接RPC,细节繁琐,用于网络数据交换场景

u3coding
A software developer

Leave a Comment

Your email address will not be published. Required fields are marked *

*