IPC轻量级实现——AIDL

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

时间: 2024-10-12 05:54:25

IPC轻量级实现——AIDL的相关文章

Android IPC通信以及AIDL技术运用

首先我们了解一下 IPC和AIDL IPC:进程间通信 AIDL:Android Interface Definition Language,即Android接口定义语言. 为什么使用: Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信. 为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现.与很多其他的基于RPC的解决方案一样,Android使用一种接

初涉IPC,了解AIDL的工作原理及用法

初涉IPC,了解AIDL的工作原理及用法 今天来讲讲AIDL.这个神奇的AIDL,也是近期在学习的,看了某课大神的解说写下的blog,希望结合自己的看法给各位同价通俗易懂的解说 官方文档:http://developer.android.com/guide/components/aidl.html 一.What is AIDL?(什么是AIDL) AIDL:Android Interface Definition Language (Android接口定义语言) 首先,我们要知道.进程1和进程2

Android进程间通信(IPC)的AIDL机制:Hello World示例

Android实现IPC可使用Android本身提供的AIDL机制.网上也有很多相关文章,但写的过于繁琐和麻烦,重点也不突出.本文抽丝剥茧从工程角度给出一个最简单的Android AIDL例程关键代码,以最简单的形式说明如何在代码中使用Android AIDL. AIDL首先在逻辑上可分为"服务端"和"客户端".在本示例中,则以两个完全不同.互相独立的Eclipse 项目代表. (1)server.一个Android App,即AIDL的服务端服务提供者. (2)c

【Android - IPC】之AIDL简介

参考资料: 1.<Android开发艺术探索>第二章2.4.4 2.Android AIDL Binder框架解析:http://blog.csdn.net/lmj623565791/article/details/38461079 3.你真的理解AIDL中的in.out.inoutm么:http://www.open-open.com/lib/view/open1469494342021.html 4.慕课网<AIDL-小白成长记> 1. AIDL简介 Android系统规定:每

IPC解决方案之 AIDL

android interface define language 跨进程通信前提:2个进程均已启动 1,跨进程启动Service Intent intent = new Intent(); //OTHER_SERVICE 另一进程Service包名+ClassNameintent.setComponent(new ComponentName(OTHER_PACKAGE, OTHER_SERVICE)); startService(intent); 2,跨进程绑定Service 2.1 Serv

Android IPC之Messenger浅谈

之前写过一篇有关 IPC之AIDL浅谈的文章,详情请看Android IPC之AIDL浅谈.今天再来介绍另一种 IPC-Messenger. 一.概述. 首先看Messenger介绍, Reference to a Handler, which others can use to send messages to it. This allows for the implementation of message-based communication across processes, by c

(转载)Android中的Service:Binder,Messenger,AIDL(2)

前言 前面一篇博文介绍了关于Service的一些基本知识,包括service是什么,怎么创建一个service,创建了一个service之后如何启动它等等.在这一篇博文里有一些需要前一篇铺垫的东西,建议没有看过前一篇博文的同学先去看一下前一篇: Android中的Service:默默的奉献者 (1) . 但是在前一篇博文中也有一些遗漏的东西--主要是关于bindService()这一块的具体细节.由于这一块涉及的东西还是比较多,所以在这里单独提出来了.闲话不多说,进入正文. 1.bindServ

IPC机制 用Messenger进行进程间通信

Messenger类可以在不同进程中传递Messge对象进行数据通信 Messenger是轻量级的IPC方案对AIDL进行了封装. 步骤: 1.在Service的onBind()方法中创建Messenger对象,并关联Handler private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_FROMCLIENT

android 远程Service以及AIDL的跨进程通信

在Android中,Service是运行在主线程中的,如果在Service中处理一些耗时的操作,就会导致程序出现ANR. 但如果将本地的Service转换成一个远程的Service,就不会出现这样的问题了. 转换成远程Service非常简单,只需要在注册Service的时候将他的android:process的属性制定成 :remote就可以了. 重新运行项目,你会发现,不会出现ANR了. 为什么将MyService转换成远程Service后就不会导致程序ANR了呢?这是由于,使用了远程Serv