对于android app开发来说android的IPC机制显得并不是这么重要,大部分的app都会是在单独进程中运行。不过对于了解android framework是非常有好处的,能够更加深入理解底层运行原理。IPC中的核心就是Binder,Binder对于应用层来说是客户端与服务器通信之后返回的Binder对象,可访问服务器方法或者与服务器传递数据。对于Framework层来说,Binder是ServiceManager与ManagerService之间的桥梁。总之,Binder在多进程通信中发挥着极为重要的作用。

IPC方式:

一、Bundle

我们知道android中的四大组件可以通过Bundle所支持的数据类型来进行跨进程通信,有一个陷阱是静态成员变量不可以在多进程中共享数据,原因是一个进程启动一个虚拟机实例,对应一个Application,也就是说当我一个进程Activity启动另外一个进程Service的时候,会创建第二个虚拟机实例,同时重新又执行了Application中的onCreate方法,这说明两个进程中的静态成员变量是互相独立的,因此无法进行数据共享。Bundle支持的数据类型包括基本数据类型、Parcelable、 Serializable等。

 

二、文件共享

文件共享就是说将一个进程中的数据序列化之后保存到文件中,其他线程需要反序列化之后才可以访问原始数据。文件共享数据需要处理好数据同步问题,如果多并发对文件进行读/写操作或者写操作,程序会产生不可预知的结果。android中特有的SharedPreferences是一种轻量级的数据存储方式,但是由于android在数据存储中会在内存中缓存数据,因此多并发下的数据共享非常不可靠,因此不建议采用。

 

三、Messenger

Messenger英文意思是信使,很好理解就是在客户端和服务器端充当信使的角色,相当于客户端和服务器端通信的媒介。Messenger底层是由AIDL(android interface define language)实现,最常用在多进程下的串行请求,服务器会把客户端发送过来的请求赛道消息队列,一个一个处理,同时如果客户端需要接受服务器返回的消息也需要通过Handler对界面更新。通过Messenger方式实现IPC流程如下:

1、Activity启动Service,Service的onBind方法返回Binder对象

2、客户端获取服务端的Messenger对象,将数据及客户端Messenger对象封装到Message,,通过Messenger发送Message到服务器端

3、服务器端通过Handler接收Message,获取Message的reply_to参数返回响应数据给客户端

4、客户端通过Handler接收数据更新UI

 

四、AIDL

这种方式是最标准的,也是最复杂的。支持多并发访问,通过Binder线程池来定位具体业务Binder来连接远程服务。

本文以图书馆图书为例,用户可以获取图书馆图书列表,也可以向列表添加图书。流程如下:

1、服务端先生成三个文件Book.java, Book.aidl和IBookManager.aidl,并且Book对象实现序列化接口Parcelable,Book.aidl文件是对Book类在AIDL中的声明,IBookManager.aidl是我们定义的对图书操作的接口包括addBook和getBookList两个方法,aidl后缀的文件需要import用到的类即使类是在同一个包下

2、生成服务端Service,新建Binder类继承IBookManager.Stub,对addBook和getBookList方法实现,onBind返回Binder对象

3、将1中生成的文件复制到客户端项目下(包名必须一致)

4、新建客户端Activity,客户端通过BindService绑定服务端,通过onServiceConnected方法获取到Binder对象,这里如果是同一个进程下,返回的是Stub对象,如果是跨进程下,返回的是proxy对象

5、通过返回的Binder对象,客户端可以访问服务器响应的addBook和getBookList方法

注意点:

1、AIDL支持基本数据类型,String和CharSequence

2、AIDL定义开头需要通过import引入需要用到的类即使类是在同一个包下

3、对象需要实现Parcelable接口,并且需要声明对象

4、支持集合类型List和Map,但是集合元素必须支持AIDL

5、AIDL文件本身也可以在AIDL文件中使用

6、除了基本类型以外的类型必须标注输入输出符号:in,out 或者inout

重要函数:

asInterface(IBinder) 服务器返回的Binder对象转换成客户端所需的AIDL接口类型的对象,如果客户端和服务器在同一个进程下,返回的是服务端本身的Stub对象;如果客户端和服务器端位于不同进程下,返回的是系统封装后的Stub.Proxy对象

asBinder 返回当前Binder对象

onTransact 此方法运行在服务器Binder线程池中,服务器端通过code参数确定客户端具体请求的是哪个方法,然后执行目标方法,当目标函数执行完成,在reply中写入返回值。需要注意的是当return false 表示客户端请求失败

Proxy#getBookList,Proxy#addBook 这两个方法都运行在客户端,执行过程是这样的:首先将输入参数和输出参数确定好,调用trasact函数发起RPC请求,同时线程挂起;然后服务器端的onTransact方法会被调用,知道RPC过程返回,当前线程继续执行,并从输出参数中获取返回结果

ps:Binder跨进程通信可以这样理解:Binder对象存储Server端和ServiceManager端的信息,Client端通过Binder的代理对象也就是Binder的内部类来translate自己的请求,Server端通过onTransact接受请求和参数并调用服务端接口定义的函数,将返回结果返回给客户端;(Linux分为用户空间和内核空间,用户空间是独立的不共享资源,而内核空间共享资源,Binder机制原理是Server端地址通过Binder驱动与内核缓存映射在一起,而Client端将资源拷贝到了内核缓存,这样Client就可以通过Binder对象直接与Server端进行通信)

 

五、Socket

套接字,是网络通信概念,分为流式套接字和用户数据报套接字两种,分别是TCP和UDP;前者是面向连接的通信方式,比较可靠;后者面向无连接的通信方式,效率较高,常用在异步通信,例如广播,确定是不保证数据一定传输成功,尤其在网络拥堵的情况下。

注意点:1、利用Socket通信需要申请INTENET及ACCESS_NETWORK_STATE权限

2、访问网络必须是在子线程中进行

 

六、ContentProvider

ContentProvider是android专门为不同应用程序提供数据共享的方式,为进程间通信而生。ContentProvider底层也是由Binder实现,因为做了封装所以还是比较简单,Content支持表格形式,文件数据,SQLite数据和对象。创建流程如下:

1、继承Contentprovider类,并重写onCreate,query,insert等方法,注意这里onCreate是运行在主线程,query等对数据操作的函数运行在Binder线程池中

2、配置文件声明读写权限,并声明1中新建的类;android:authorities,android:name;android:permission;android:process

3、activity可以通过ContentResolver来访问ContentProvider共享的数据

 

更多相关文章

  1. Android之Media播放器源码分析(framework——native)
  2. Android(安卓)内存泄漏调试
  3. Android的SQLite学习及使用方法(1)
  4. Android(安卓)中关于Cursor类的介绍
  5. [置顶] 进击的Android注入术《五》
  6. 在Android中使用Handler和Thread线程执行后台操作
  7. Android(安卓)cursor用法
  8. Android——SQLite实现面向对象CRUD
  9. Android(安卓)数据Parcel序列化过程源码分析

随机推荐

  1. Activity-RelativeLayout
  2. Android的设计模式-代理模式
  3. Android的设计模式-解释器模式
  4. 50个Android开发人员必备UI效果源码
  5. Android的设计模式-原型模式
  6. Android的设计模式-桥接模式
  7. 50个Android开发人员必备UI效果源码
  8. Android的设计模式-迭代器模式
  9. Android的设计模式-访问者模式
  10. [Android]Android布局文件中的android:id