Android进程间通信:
Binder: 只有 IPC(进程间通信) 没有多线程 多个应用程序
Message:只有IPC 没有多线程
AIDL:IPC 多线程 多个应用程序 基于Service实现
AIDL默认支持的数据类型:
基本数据类型(除了short类型外,因为序列化中没有short方法)
String,CharSequence
List,Map
Parcelable
使用
远程调用基本类型数据:
1.AS中创建一个应用,在应用中创建aidl文件夹,然后在文件夹里面创建一个AIDL文件,如图所示:
在IExampleAidl.aidl文件会自动生成一个接口和方法,方法可以自己定义,我这里实现两个数的相加
// IExampleAidl.aidl package com.example.androidaidltest; // Declare any non-default types here with import statements interface IExampleAidl { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ int add(int num1,int num2); }然后点击AS进行编译,如图:
自定义一个Service类继承Service,实现aidl方法中的接口
public class ExampleService extends Service { //客户端绑定该服务的时候就会调用该接口 @Nullable @Override public IBinder onBind(Intent intent) { return binder; } private IBinder binder=new IExampleAidl.Stub(){ @Override public int add(int num1, int num2) throws RemoteException { Log.v("test","来自客户端的数据num1="+num1+" num2="+num2); return num1+num2; } }; }
这里注意,在服务端的manifest清单文件中,要见启动服务更改成自定义的Service
然后创建一个新的moudle作为客户端,并且将服务端的AIDL文件复制到客户端的对应目录下面,注意,客户端与服务端AIDL的包名必须一致,如图:<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <service android:name=".ExampleService"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </service> </application>
编译客户端的AIDL文件
在客户端调用远程服务:
通过binderService绑定远程服务
private void bindMyService() { Intent intent=new Intent(); intent.setComponent(new ComponentName("com.example.androidaidltest","com.example.androidaidltest.ExampleService")); bindService(intent,conn, Context.BIND_AUTO_CREATE); }在 ServiceConnection中通过 asInterface方法 获取远程服务的代理
ServiceConnection conn=new ServiceConnection() { //绑定上服务的时候 @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { //获取远程服务,此处为远程服务的代理Proxy myAidl= IExampleAidl.Stub.asInterface(iBinder); } //断开的时候 @Override public void onServiceDisconnected(ComponentName componentName) { //回收资源 myAidl=null; } };获取远程服务对象之后,就可以调用其中的方法了,先运行服务端,再运行客户端,服务端没有界面。
具体实现参见链接中的demo:
http://download.csdn.net/detail/luck_136/9606080
远程调用自定义对象:
自定义javaBean对象,实现Parcelable接口,并实现对应的方法,同时还要实现Creator<T>静态接口,eg:
public static final Creator<Persion> CREATOR=new Creator<Persion>() { @Override public Persion createFromParcel(Parcel parcel) { return new Persion(parcel); } @Override public Persion[] newArray(int i) { return new Persion[i]; } };在AIDL文件中添加对应的JavaBean的AIDL文件,这里以Persion为例,该 Persion.aidl文件中的内容为:
// IPersion.aidl package com.example.aidlpersion; // Declare any non-default types here with import statements import com.example.aidlpersion; parcelable Persion;然后在原来的AIDL文件中使用Persion,这里要注意导入Persion的包,如图
IPersion.aidl中的内容为:
// IPersion.aidl package com.example.aidlpersion; // Declare any non-default types here with import statements import com.example.aidlpersion.Persion; interface IPersion { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ List<Persion> add(in Persion p); }这里的“in” 表示输入
然后对服务器端进行编译,其他处理跟传递基础类型数据是一样的,另外也要讲自定义的对象复制到客户端,并且包名也要跟服务端一致
具体实现见以下链接中的demo:
http://download.csdn.net/detail/luck_136/9606084
AIDL原理简单解析:
首先来看如下图示:
通过图示我们可以看到服务端初始化了内部类Stub,客户端通过asInterface获取远程服务的代理Proxy,而功能的实现是通过transact调用,transact又调用了onTransact.下面看看里面的代码逻辑。我们将.aidl文件进行编译会在build——>generated——>source——>aidl——>debug目录下生成对应的java文件,如下图所示:
我们来看看java文件IPersion中的代码
我们看到整个文件就是跟我们定义的aidl文件是一致的,只是多了一个Stub的抽象存根类,那么下面看看Stub里面有做了什么:
/** 存根抽象类类*/ public static abstract class Stub extends android.os.Binder implements com.example.aidlpersion.IPersion { private static final java.lang.String DESCRIPTOR = "com.example.aidlpersion.IPersion"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.aidlpersion.IPersion interface, * generating a proxy if needed. */ public static com.example.aidlpersion.IPersion asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.aidlpersion.IPersion))) { return ((com.example.aidlpersion.IPersion)iin); } return new com.example.aidlpersion.IPersion.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_add: { data.enforceInterface(DESCRIPTOR); com.example.aidlpersion.Persion _arg0; if ((0!=data.readInt())) { _arg0 = com.example.aidlpersion.Persion.CREATOR.createFromParcel(data); } else { _arg0 = null; } java.util.List<com.example.aidlpersion.Persion> _result = this.add(_arg0); reply.writeNoException(); reply.writeTypedList(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.aidlpersion.IPersion { 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; } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ @Override public java.util.List<com.example.aidlpersion.Persion> add(com.example.aidlpersion.Persion p) 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.aidlpersion.Persion> _result; try { _data.writeInterfaceToken(DESCRIPTOR); if ((p!=null)) { _data.writeInt(1); p.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.example.aidlpersion.Persion.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); }
先看Stub类中asInterface方法
/** * Cast an IBinder object into an com.example.aidlpersion.IPersion interface, * generating a proxy if needed. */ public static com.example.aidlpersion.IPersion asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.aidlpersion.IPersion))) { return ((com.example.aidlpersion.IPersion)iin); } return new com.example.aidlpersion.IPersion.Stub.Proxy(obj); }可以看到asInterface返回一个IPersion的对象,但是其内部是通过Proxy拿到的IPersion对象
再看看内部类Proxy
private static class Proxy implements com.example.aidlpersion.IPersion { 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; } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ @Override public java.util.List<com.example.aidlpersion.Persion> add(com.example.aidlpersion.Persion p) 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.aidlpersion.Persion> _result; try { _data.writeInterfaceToken(DESCRIPTOR); if ((p!=null)) { _data.writeInt(1); p.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.example.aidlpersion.Persion.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } }可以看到Proxy内部调用了 mRemote .transact( Stub. TRANSACTION_add , _data, _reply, 0 )方法
而我们可以看到在Stub类中有一个onTransact()方法
@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_add: { data.enforceInterface(DESCRIPTOR); com.example.aidlpersion.Persion _arg0; if ((0!=data.readInt())) { _arg0 = com.example.aidlpersion.Persion.CREATOR.createFromParcel(data); } else { _arg0 = null; } java.util.List<com.example.aidlpersion.Persion> _result = this.add(_arg0); reply.writeNoException(); reply.writeTypedList(_result); return true; } } return super.onTransact(code, data, reply, flags); }可以看到在onTransact通过code来进行判断,之前调用 transact方法的时候我们是传入了一个Stub.TRANSACTION_add的值,这个值就是一个code,在Stub中定义了,当code值为TRANSACTION_add,在远程的方法中做相关的操作。
至此,利用AIDL完成进程间通信的过程就分析完成了,主要就是用到了代理模式,利用Server的IBinder完成的。