原文地址:http://blog.csdn.net/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实现通信,重要程度不言而喻,特此推荐了解一下,如果我理解透彻了会出续篇,有好文可以在留言区推荐哦,笔者在此感谢了。