我们从三个方面来对AIDL进行了解:
1)介绍
2)定义
3)实例
一 介绍
AIDI(Android接口定义语言),它是Android中用来解决进程间通信的一个桥梁,它的内部实现是binder,是IPC机制的一种轻量级的实现,在Android中提供了自动创建stub的工具。
二 定义
AIDL从它的名字就可以知道,它是一个接口类型的文件,但是它与java中定义的接口有不同的地方:
1)支持的类型不一样:
AIDL支持的类型:
1,基本的数据类型(int、long、char等)
2,String、CharSequence、List(ArrayList)、Map(HashMap)等
3,所有实现Parcelable接口的对象
4,所有的AIDL接口
2)除了基本的数据类型,自定义的Parcelable对象和AIDL接口都必须显示的import进来,不管它们是否在同一个包中
3)除了基本的数据类型,其他数据类型的参数必须标上方向:in(输入型)、out(输出型)、inout(输入输出型),在使用时要限制使用的方向,因为在底层实现是很需要开销的。
三 实例
1)创建AIDL实例
先创建一个JavaBean:Car
package com.swun.tinama.aidl_demo; import android.os.Parcel; import android.os.Parcelable; /** * Created by Administrator on 2016/5/8. */ public class Car implements Parcelable { public int getCarID() { return carID; } @Override public String toString() { return "Car{" + "carID=" + carID + ", carName='" + carName + '\'' + '}'; } public void setCarID(int carID) { this.carID = carID; } public String getCarName() { return carName; } public void setCarName(String carName) { this.carName = carName; } private int carID; private String carName; protected Car(Parcel in) { carID = in.readInt(); carName = in.readString(); } public Car(int carID, String carName) { this.carID = carID; this.carName = carName; } public static final Creator<Car> CREATOR = new Creator<Car>() { @Override public Car createFromParcel(Parcel in) { return new Car(in); } @Override public Car[] newArray(int size) { return new Car[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(carID); dest.writeString(carName); } }
Car类实现了Parcelable,这样Car的对象就可以在AIDL中传递了,既然想在AIDL中传递就要创建一个Car.aidl文件
// Car.aidl package com.swun.tinama.aidl_demo; parcelable Car;
接着创建一个管理Car的接口:
// ICarFactory.aidl package com.swun.tinama.aidl_demo; import com.swun.tinama.aidl_demo.Car; import com.swun.tinama.aidl_demo.IOnNewCarArrivedListener; interface ICarFactoryManager { void addCar(in Car car); void remove(in Car car); List<Car> getCars(); void registListener(IOnNewCarArrivedListener listener); void unRegistListener(IOnNewCarArrivedListener listener); }
可以看到,虽然Car类是和ICarFactoryManager是在一个工厂中,但是还要import Car的路径,IOnNewCarArrivedListener是当service在car工厂添加进一辆车后,通知client,它的实现是:
// IOnNewCarArrivedListener.aidl package com.swun.tinama.aidl_demo; import com.swun.tinama.aidl_demo.Car; // Declare any non-default types here with import statements interface IOnNewCarArrivedListener { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); void onNewCarArrived(in Car car); }
在AndroidStudio中点击Build/make project后会在gen下生成对应的java文件:
我们选择IOnNewCarArrivedList.java来看看内部的实现:
/* * This file is auto-generated. DO NOT MODIFY. * Original file: E:\\git\\AIDL_demo\\app\\src\\main\\aidl\\com\\swun\\tinama\\aidl_demo\\IOnNewCarArrivedListener.aidl */ package com.swun.tinama.aidl_demo; // Declare any non-default types here with import statements public interface IOnNewCarArrivedListener extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.swun.tinama.aidl_demo.IOnNewCarArrivedListener { private static final java.lang.String DESCRIPTOR = "com.swun.tinama.aidl_demo.IOnNewCarArrivedListener"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.swun.tinama.aidl_demo.IOnNewCarArrivedListener interface, * generating a proxy if needed. */ public static com.swun.tinama.aidl_demo.IOnNewCarArrivedListener asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.swun.tinama.aidl_demo.IOnNewCarArrivedListener))) { return ((com.swun.tinama.aidl_demo.IOnNewCarArrivedListener)iin); } return new com.swun.tinama.aidl_demo.IOnNewCarArrivedListener.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_basicTypes: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); long _arg1; _arg1 = data.readLong(); boolean _arg2; _arg2 = (0!=data.readInt()); float _arg3; _arg3 = data.readFloat(); double _arg4; _arg4 = data.readDouble(); java.lang.String _arg5; _arg5 = data.readString(); this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5); reply.writeNoException(); return true; } case TRANSACTION_onNewCarArrived: { data.enforceInterface(DESCRIPTOR); com.swun.tinama.aidl_demo.Car _arg0; if ((0!=data.readInt())) { _arg0 = com.swun.tinama.aidl_demo.Car.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.onNewCarArrived(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.swun.tinama.aidl_demo.IOnNewCarArrivedListener { 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 void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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.writeInt(anInt); _data.writeLong(aLong); _data.writeInt(((aBoolean)?(1):(0))); _data.writeFloat(aFloat); _data.writeDouble(aDouble); _data.writeString(aString); mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void onNewCarArrived(com.swun.tinama.aidl_demo.Car car) 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 ((car!=null)) { _data.writeInt(1); car.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_onNewCarArrived, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_onNewCarArrived = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException; public void onNewCarArrived(com.swun.tinama.aidl_demo.Car car) throws android.os.RemoteException; }
首先,所有的AIDL都是要继承IInterface,它生成了一个内部类Stub,Stub就是Binder,所以我们在service.onBind中返回的就是Stub的一个对象,asInterface()是把binder对象转换成我们所需要的AIDL对象,这样service就给client暴漏了一个端口,client就可以从onBind中拿到binder,然后拿到所需要的AIDL对象,这样就可以调用远程service中的方法。
asInterface:queryLocalInterface()是判断客户端与服务端是否在同一个进程中,如果是,就得到服务端的binder,否则就得到Stub.Proxy对象
Proxy是binder的真正实现,当client调用onNewCarArrived时就是调用Proxt中的方法,该方法首先会把数据序列化到二进制流中,然后调用Stub中的transact(),transact通过标示符来选择调用binder中不同的方法,binder中的方法是我们在service中自己实现的,这里是要对数据进行反序列化的,所有说自定义的类要实现Parcelable。
下面我们来看看service、client是怎么实现的:
service:
package com.swun.tinama.aidl_demo.Service; import android.app.Service; import android.content.Intent; import android.os.*; import android.support.annotation.Nullable; import android.util.Log; import com.swun.tinama.aidl_demo.Car; import com.swun.tinama.aidl_demo.ICarFactoryManager; import com.swun.tinama.aidl_demo.IOnNewCarArrivedListener; import com.swun.tinama.aidl_demo.utils.MyUtils; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; /** * Created by Administrator on 2016/5/8. */ public class CarManagerService extends Service { private static final String TAG = "CarManangerService"; private AtomicBoolean mAtomicBoolean = new AtomicBoolean(false); private CopyOnWriteArrayList<Car> mCarList = new CopyOnWriteArrayList<Car>(); // private CopyOnWriteArrayList<IOnNewCarArrivedListener> mListeners = new CopyOnWriteArrayList<IOnNewCarArrivedListener>(); private RemoteCallbackList<IOnNewCarArrivedListener> mListeners = new RemoteCallbackList<IOnNewCarArrivedListener>(); private IBinder binder = new ICarFactoryManager.Stub() { @Override public void addCar(Car car) throws RemoteException { mCarList.add(car); } @Override public void remove(Car car) throws RemoteException { mCarList.remove(car); } @Override public List<Car> getCars() throws RemoteException { return mCarList; } @Override public void registListener(IOnNewCarArrivedListener listener) throws RemoteException { // mListeners.add(listener); mListeners.register(listener); } @Override public void unRegistListener(IOnNewCarArrivedListener listener) throws RemoteException { // mListeners.remove(listener); mListeners.unregister(listener); } }; @Override public void onCreate() { super.onCreate(); mCarList.add(new Car(1, "奥迪")); mCarList.add(new Car(2, "大众")); Log.i(TAG, MyUtils.getCurrentProcessName(this)); new Thread(new FactoryWroker()).start(); } private class FactoryWroker implements Runnable { @Override public void run() { while (!mAtomicBoolean.get()) { try { Thread.sleep(1000); int carID = mCarList.size() + 1; Car car = new Car(carID, "new car#" + carID); onNewCarArrived(car); } catch (InterruptedException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } } } } @Nullable @Override public IBinder onBind(Intent intent) { return binder; } private void onNewCarArrived(Car car) throws RemoteException { Log.i(TAG, "new car arrived" + car.toString()); mCarList.add(car); /*for (IOnNewCarArrivedListener listener : mListeners) { listener.onNewCarArrived(car); }*/ int count = mListeners.beginBroadcast(); for (int i = 0; i < count; i++) { IOnNewCarArrivedListener listener = mListeners.getBroadcastItem(i); if (listener != null) { listener.onNewCarArrived(car); } } mListeners.finishBroadcast(); } @Override public void onDestroy() { mAtomicBoolean.set(true); super.onDestroy(); } }
client:
package com.swun.tinama.aidl_demo; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import com.swun.tinama.aidl_demo.Service.CarManagerService; import com.swun.tinama.aidl_demo.utils.MyUtils; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private Handler mHandler = new Handler(); private ICarFactoryManager mTmpFactoryManager; private IOnNewCarArrivedListener carArrivedListener = new IOnNewCarArrivedListener.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public void onNewCarArrived(final Car car) throws RemoteException { mHandler.post(new Runnable() { @Override public void run() { Log.i(TAG, "接收到新的车的通知啦!" + car.toString()); } }); } }; private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { ICarFactoryManager carFactoryManager = ICarFactoryManager.Stub.asInterface(service); try { mTmpFactoryManager = carFactoryManager; List<Car> cars = carFactoryManager.getCars(); printCarInformation(cars); cars.add(new Car(3, "奔驰")); printCarInformation(cars); carFactoryManager.registListener(carArrivedListener); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; void printCarInformation(List<Car> cars) { Log.i(TAG, cars.toString()); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i(TAG, MyUtils.getCurrentProcessName(this)); } @Override protected void onDestroy() { /*if (mTmpFactoryManager != null && mTmpFactoryManager.asBinder().isBinderAlive()) { try { Log.i(TAG,"注销Listener!"); mTmpFactoryManager.unRegistListener(carArrivedListener); } catch (RemoteException e) { e.printStackTrace(); } }*/ unbindService(mServiceConnection); super.onDestroy(); } public void UNREGIST(View v) { if (mTmpFactoryManager != null && mTmpFactoryManager.asBinder().isBinderAlive()) { try { Log.i(TAG, "注销Listener!"); mTmpFactoryManager.unRegistListener(carArrivedListener); } catch (RemoteException e) { e.printStackTrace(); } } } public void CLICK(View v) { Intent intent = new Intent(this, CarManagerService.class); bindService(intent, mServiceConnection, BIND_AUTO_CREATE); } }
为了模仿在不同的进程,在AndroidManifest.xml中service配置为:
<service android:name=".Service.CarManagerService" android:process=":second"></service>
这样通过Log就可以看到实现了在不同的进程之间进行通信:
可以看到当我们UNREGIST按钮后,client就不会收到消息
源码已经提交到github上 https://github.com/522363215/AIDL_demo/tree/master
温馨提示:
1)我们在使用List时,可以使用CopyOnWriteArrayList,它实现了List接口,而且它支持并发读/写
2)binder中对数据的处理是通过序列化和反序列化的,若我们想获取通过binder处理后相同的对象,可以使用RemoteCallBackList,它内部自动实现了线程同步的功能
到此,AIDL的介绍就完了,谢谢大家的观看!