原文地址:http://blog.youkuaiyun.com/verymrq/article/details/72885825
说到进程,刚开始学Android的时候无法理解进程和线程的区别,我的理解是:线程就是工作台,完成一件工艺品需要多道工序(可同时操作此作品,其中就涉及到线程安全),而进程是车间,当工厂越来越大,你需要的工作空间(内存)越来越多,就需要再建一个车间来作业了,进程就是如此。
我们新建一个进程很简单:
<activity
android:name="com.example.MyProcessActivity"
android:process=":text.process" >
</activity>
只需要在activity中加入process属性即可。
但是一旦不在同一个进程中,就无法正常的通信及共享数据,这也就需要用到Android的IPC机制:进程间通信了。其实,就我目前了解,进程间通信有:contenProvider、Messenger、binder、Broadcast等等,归根结底其余几种原理都是binder,不仅如此,其实应用间通讯、及应用与系统通讯都用到了binder,为啥这个binder这么牛逼呢?
其实我在网上看了各路大神都对binder很重视,就在我看了包建强老师这几篇文章后理解更加深刻了:戳我看原文
说到binder当然离不开aidl文件咯。相信我们大多数童鞋接触binder都是这样一个场景:新建一个aidl文件xxInterface.aidl,rebuild之后系统会帮我们生成xxInterface.java,然后在service里新建这个类的内部类stub对象并重写aidl里的方法,在onbind里返回这个对象,再通过ServiceConnection得到,就能调用了。这个流程以及aidl是什么鬼,不懂的童鞋可以自行谷歌/百度关键字,我就不多逼逼了。
这里我想记录的是这个流程背着我们干了些啥,那我就从系统自动生成的文件搞起。这里我新建一个IUserInterface.aidl,只写了一个addUser方法,于是生成以下文件:
public interface IUserInterface extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.example.mybinderpool.IUserInterface {
private static final java.lang.String DESCRIPTOR = "com.example.mybinderpool.IUserInterface";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static com.example.mybinderpool.IUserInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.mybinderpool.IUserInterface))) {
return ((com.example.mybinderpool.IUserInterface) iin);
}
return new com.example.mybinderpool.IUserInterface.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_addUser: {
data.enforceInterface(DESCRIPTOR);
com.example.mybinderpool.User _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.mybinderpool.User.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addUser(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.mybinderpool.IUserInterface {
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 void addUser(com.example.mybinderpool.User user) 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 ((user != null)) {
_data.writeInt(1);
user.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void addUser(com.example.mybinderpool.User user) throws android.os.RemoteException;
}
是的,我第一次看这玩意也想的是:什么乱七八糟的,不了了之。后来我看了安卓艺术探索对binder的介绍之后,慢慢理清其中的脉络。
首先,我们知道我们在service里要新建一个stub,然后通过Onbind返回
public static abstract class Stub extends android.os.Binder implements com.example.mybinderpool.IUserInterface{
//代码省略
}
嘛,继承了binder,难怪要把这个stub传来传去,传的就是binder对象而已。
传过去之后呢,是不是在connection里干了这么件事:
public void onServiceConnected(ComponentName name, IBinder service) {
binder = XXInterface.Stub.asInterface(service);
}
调用了asInterface方法嘛,我们看看这个方法干了些啥:
public static com.example.mybinderpool.IUserInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//先在所在进程看看有没有这个binder
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.mybinderpool.IUserInterface))) {
//如果有,就直接返回
return ((com.example.mybinderpool.IUserInterface) iin);
}
//没有就返回这个proxy
return new com.example.mybinderpool.IUserInterface.Stub.Proxy(obj);
}
所在进程如果有,直接返回了,就不涉及到别的进程了,这里我不管他,看这个proxy,看名字就熟悉,stub内部类嘛,翻译过来就是代理的意思,哦,下意识想到代理模式(不了解的自行搜索关键字),好吧,那我们再看看这个proxy。
private static class Proxy implements com.example.mybinderpool.IUserInterface {
//remote翻译过来就是远程,这里代理了其他进程的binder
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 void addUser(com.example.mybinderpool.User user) 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 ((user != null)) {
_data.writeInt(1);
user.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
//关键处,调用了远程binder的transact方法。
mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
proxy重写了addUser方法,也就是说刚刚通过asInterface得到的对象调用的就是这个方法咯。在addUser方法里所做的也就是把数据_data及返回_reply这两个Parcel对象(进程间对象必须是parcelable的,应该都懂吧)通过远程对象的transact方法传了出去,通过查阅资料,阅读源码我们知道了transact方法会调用onTransact方法哦:
这个onTransact方法好熟悉,等等,我就要想起来了!不就是stub里面的方法嘛,不信?你倒回去看看。
对吧,没骗你,于是我们惊喜的发现:
调用了stub的addUser方法!!!这个stub可是你从其他进程里传过来的哦,至于addUser方法也是你自己重写的。
好的,binder简单实现已经梳理完成,我们可以发现,你如果想的话,自己写一个XXinterface就行,甚至可以不需要写aidl文件,当然既然可以简便当然最好咯,自己实现也是Copy。
在此申明一下,本文仅仅是研究binder在Android开发人员的接触范围,至于底层C++实现对于开发人员的我来说暂时接触不到,或许以后感兴趣了倒回去再看看,有兴趣的童鞋也可以自行搜索。
最后:由于Android四大组件都是通过binder实现通信,重要程度不言而喻,特此推荐了解一下,如果我理解透彻了会出续篇,有好文可以在留言区推荐哦,笔者在此感谢了。