码迷,mamicode.com
首页 > 其他好文 > 详细

IPC轻量级实现——AIDL

时间:2016-05-12 20:22:29      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:

我们从三个方面来对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的介绍就完了,谢谢大家的观看!






IPC轻量级实现——AIDL

标签:

原文地址:http://blog.csdn.net/qq_22218005/article/details/51351534

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!