IPC轻量级实现——AIDL

来源:互联网 发布:java常用泛型方法 编辑:程序博客网 时间:2024/05/17 23:27

我们从三个方面来对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.aidlpackage com.swun.tinama.aidl_demo;parcelable Car;
接着创建一个管理Car的接口:

// ICarFactory.aidlpackage 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.aidlpackage com.swun.tinama.aidl_demo;import com.swun.tinama.aidl_demo.Car;// Declare any non-default types here with import statementsinterface 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 statementspublic 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的介绍就完了,谢谢大家的观看!






0 0
原创粉丝点击