IPC—Inter-Process Communication 进程间通信
线程是 CPU调度的最小单元,同时线程是一种有限的系统资源;进程一般指一个执行单元,在PC和移动设备上指一个程序或一个应用。一个进程可以包含多个线程;
Android中的主线程也叫UI线程,在UI线程里才能操作界面元素。
在Andorid中开启多进程模式:给四大组件在AndroidManifest.xml中指定android:process属性。
PS:进程名以“:”开头的进程属于当前应用的私有进程,其他应用不可以和它泡在同一个进程中,而进程名不以“:”开头的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。
多进程模式的运行机制:Android为每个进程都分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的的地址空间,这会导致不同的虚拟机在访问同一个类的对象会产生多份副本。
PS:一般来说,使用多进程会造成以下问题:
1.静态成员和单例模式完全失效;
2.线程同步机制完全失效;
3.SharedPreferences的可靠性下降;
4.Application会多次创建;
序列化与反序列(Serializable&&Parcelable)
序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
Serializable和Parcelable接口可以完成对象的序列化过程(当我们需要通过Intent和Binder传输数据或把对象持久化DAO存储设备上或通过网络传输给其他客户端)
Serializable是java所提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化与反序列化操作;
PS:静态成员变量属于类不属于对象,不会参与序列化过程;
用transient关键字标记的成员变量不参与序列化过程;
Parcelable也是一个接口,只要实现这个接口,一个类的对象就可以实现序列化并可以通过Intent和Binder传递。
(Parcelable:在序列化过程中需要实现的功能有序列化(writeToParcel),反序列化(CREATER),内容描述(describeContents))
比较:Serializable是java中的序列化接口,其使用起来简单但是开销很大,序列化和反序列化过程需要大量I/O操作;Parcelable是Android中的序列化方式,因此更适合在Android平台上,它的缺点是使用起来稍微麻烦点,但是效率很高,推荐使用;Parcelable主要用于在内存序列化上,若将对象序列化到存储设备中或将对象序列号后通过网络传输建议使用Serializable。
Binder:从Android应用层来说,Binder是客户端和服务端进行通信的媒介;
Binder类
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\AndroidTest\\IPCbyAIDL\\app\\src\\main\\AIDL\\com\\example\\admin\\ipcbyaidl\\IBookManager.aidl
*/
package com.example.admin.ipcbyaidl;
public interface IBookManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.admin.ipcbyaidl.IBookManager
{
private static final java.lang.String DESCRIPTOR = "com.example.admin.ipcbyaidl.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.admin.ipcbyaidl.IBookManager interface,
* generating a proxy if needed.
*/
public static com.example.admin.ipcbyaidl.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.admin.ipcbyaidl.IBookManager))) {
return ((com.example.admin.ipcbyaidl.IBookManager)iin);
}
return new com.example.admin.ipcbyaidl.IBookManager.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.admin.ipcbyaidl.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:
{
data.enforceInterface(DESCRIPTOR);
com.example.admin.ipcbyaidl.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.admin.ipcbyaidl.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_registerListener:
{
data.enforceInterface(DESCRIPTOR);
com.example.admin.ipcbyaidl.IOnNewBookArrivedListener _arg0;
_arg0 = com.example.admin.ipcbyaidl.IOnNewBookArrivedListener.Stub.asInterface(data.readStrongBinder());
this.registerListener(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_unregisterListener:
{
data.enforceInterface(DESCRIPTOR);
com.example.admin.ipcbyaidl.IOnNewBookArrivedListener _arg0;
_arg0 = com.example.admin.ipcbyaidl.IOnNewBookArrivedListener.Stub.asInterface(data.readStrongBinder());
this.unregisterListener(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.admin.ipcbyaidl.IBookManager
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.util.List<com.example.admin.ipcbyaidl.Book> getBookList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.admin.ipcbyaidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.admin.ipcbyaidl.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addBook(com.example.admin.ipcbyaidl.Book book) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void registerListener(com.example.admin.ipcbyaidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener!=null))?(listener.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public void unregisterListener(com.example.admin.ipcbyaidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((listener!=null))?(listener.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
}
public java.util.List<com.example.admin.ipcbyaidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.example.admin.ipcbyaidl.Book book) throws android.os.RemoteException;
public void registerListener(com.example.admin.ipcbyaidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException;
public void unregisterListener(com.example.admin.ipcbyaidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException;
}
asInterface(android.os.IBinder obj)
用于将服务器的Binder对象转化为客户端所需AIDL接口类型的对象(这种转化过程是区分进程的,如果客户端服务端位于同一个进程,则返回服务端的Stub对象本身,否则返回的是系统封装后的Stub.proxy对象。
asBinder
此方法用于返回当前Binder对象。
PS:1.当客户端发起远程请求时,由于当前线程会被挂起直到服务端进程返回数据,所以如果一个远程方法是耗时的,则不能再UI线程中发起此远程请求;
2.由于服务器的Binder方法运行在Binder的线程池中,所以Binder方法不管是否耗时,都应该采用同步的方法去实现。
Android中的IPC方式
Bundle 文件共享 Messenger AIDL ContentProvider Socket
AIDL文件支持的数据类型:
1.基本数据类型;
2.String 和CharSequence;
3.List:只支持ArrayList,里面的每个元素必须都能被AIDL支持;
4.Map:只支持HashMap,里面的每个元素都必须被AIDL支持,包括Key和value;
5.Parcelable:所有实现了Parcelable接口的对象;
6.AIDL:所有的AIDL接口本身也可以在AIDL文件中使用;
Bundle:四大组件的的进程间通信
简单易用——只能传输Bundle支持的数据类型
文件共享:无并发访问情形,交换简单的数据实时性不高的场景
简单易用——不适合高并发场景,并且无法做到进程间的即时通信
AIDL:一对多通信且有RPC需求
功能强大,支持一对多并发通信,支持实时通信——使用稍复杂,需要处理好线程同步
Messenger:低并发的一对多即时通信,无RPC(远程进程调用)需求,或者不需要返回结果的RPC需求
功能一般,支持一对串行通信,支持实时通信——不能很好处理高并发情形,不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型
CotentProvider:一对多的进程间的数据共享
在数据源访问方面功能强大,支持一对多并发数据共享,可通过Call方法扩展其他操作——可以理解为受约束的AIDL,主要提供数据源的CRUD操作
Socket——网路数据交换
功能强大,可以通过网络传输字节流,支持一对多并发实时通信——实现细节稍微有点琐碎,不支持直接的RPC
参考资料:《Android开发技术探索》——第2章 IPC机制