1. 远程调用的数据传输
在远程的函數中,必然会需要传递一些数据,那这些数据是怎么传输的呢?
在IPC中,Proxy端的作用就是将一些参数打包,然后发送出去,下面是在Proxy端经常会遇见的调用远程方法的代码。
可以看到,发送和接收的数据都是通过Parcel來打包的。
1 class ActivityManagerProxy implementsIActivityManager2 {3 public intstartActivity(IApplicationThread caller, Intent intent,4 String resolvedType, IBinder resultTo, String resultWho, intrequestCode,5 intstartFlags, String profileFile,6 ParcelFileDescriptor profileFd, Bundle options) throwsRemoteException {7 Parcel data =Parcel.obtain();8 Parcel reply =Parcel.obtain();9 data.writeInterfaceToken(IActivityManager.descriptor);10 data.writeStrongBinder(caller != null ? caller.asBinder() : null);11 intent.writeToParcel(data, 0);12 data.writeString(resolvedType);13 data.writeStrongBinder(resultTo);14 data.writeString(resultWho);15 ...16 mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);17 reply.readException();18 int result =reply.readInt();19 ...20 returnresult;21 }22 }
一些基本类型,比如String,int可以直接写进Parcel中,那么对于一些比较复杂的数据类型,比如一些自己定义的对象,要怎么写进Parcel里呢?
我們通过一个类new一个对象時,这个object的有效范围只是在一个进程里。如果通过IPC机制直接传递一个object是不现实的。因为Java环境里的对象是通过引用來访问的,一个object对其他object,会是通过一个类似指针的引用來访问的,会涉及到类似地址的访问。
所以在传递复杂对象時,必须把object拆解成中间形式,然後在IPC里传输这种中间格式。
那怎么把一个object拆解成中间形式呢?
-->這裏就需要Parcelable接口了
2.Parcelable
当需要在进程间传输一个object時,这个object必須实现Parcelable接口的属性或方法。
例如:
在单进程中,有这样一个类:
1 classTaskInfo {2 public intmPid;3 public intmUid;4 publicString mPackageName;5
6 TaskInfo () {7 mPid = -1;8 mUid = -1;9 mPackageName = null;10 }
在实现了Parcelable后,就可以跨进程传输了,定义的TaskInfo类:
1 public class TaskInfo implementsParcelable {2 public intmPid;3 public intmUid;4 publicString mPackageName;5
6 TaskInfo () {7 mPid = -1;8 mUid = -1;9 mPackgeName = null;10 }11 public int describeContents() { //返回值描述Parcel是起什么作用的,一般是0.
12 return 0;13 }14
15 public void writeToParcel(Parcel out, int flags) { //用于发送,把需要传输的属性写入Parcel。
16 out.writeInt(mPid);17 out.writeInf(mUid);18 out.writeString(mPackageName);19 }20
21 public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {//对应writeToParcel(),接收端process会把Parcel object的中间object回复出來,传递新对象。
22 public TaskInfo createFromParcel(Parcel in) {//初始化 Parcel object
23 return newTaskInfo(in);24 }25
26 public TaskInfo[] newArray(int size) {//用于创建多个空对象,使用默认的初始化方法。
27 return newTaskInfo[size];28 }29 };30 private TaskInfo(Parcel in) {//使用Parcel的readInt()、readLong()等方法从Parcel里读出來
31 mPid =in.readInt();32 mUid =in.readInt();33 mPackageName =in.readString();34 }35 }
3.Parcel的传送
对于Parcel的传输,我们可以比喻成用传真机來发送一个纸盒子到远方。传真机不是時空传送带,并不会真正可以实现某个物品的跨进程传送,但可以变通來完成:
(这部分是从网上看到的,但忘了网址是啥了。。)
这样,传送一个纸盒子就可以分为三个部分了:
1.把纸盒拆解,得到平面化的图形。
2.把平面化的图形通过传真及传到远端。
3.远端的传真机收到平面化的图形后,就可以打印到纸上,再裁剪,粘帖,就可以得到一個一模一样的紙盒子了。
所以,我們在发送時,可以认为是把对象進行拆解打包,然后塞进Parcel对象里。Parcel就相当于是容器,其中会有一段buffer存放中间结果。这个过程会是通过writeToParcel()方法,将对象的属性拆开,填写到Parcel的buffer中。
而读取端,会通过某种方法,將Parcel读取出來。
unflatten操作是通过CREATOR的createFromParcel()來完成。
4.Parcel支持的数据类型
Parcel能支持的數據類型有:
null
String
Byte
Short
Integer
Long
Float
Double
Boolean
String[]
boolean[]
byte[]
int[]
long[]
Object[]
Bundle
Map
Parcelable
Parcelable[]
CharSequence
List
SparseArray
IBinder
Serializable
看,IBinder是可以在进程间传输的!