Android 学习笔记之AIDL通信

191 阅读3分钟

什么是AIDL?

AIDL是Android开发者实现跨进程通信使用的类,内部实现Binder机制,方便开发者调用。 AIDL类似一个中间代理,开发者想跨进程,使用AIDL,AIDL实现其中各种规则,实现Binder调用。

AIDL使用

先看一下AIDL在Android开发中的使用

创建两个工程,一个client发送端,一个Service服务端

1、client发送端重点代码

看下Client端代码架构,创建要使用的两个AIDL

image.png

IMyAidl AIDL 类

interface IMyAidl {
    void addPerson(in Person person);

    List<Person> getPersonList();

    void setData(in byte[] data);
}

Person AIDL类

parcelable Person;

Person普通类,实现pracelable.

Activity中操作首先对服务端Service绑定

private void bindService() {
    Intent intent = new Intent();
    intent.setComponent(new ComponentName("com.enjoy.service", "com.enjoy.service.MyAidlService"));//需要交互的服务端注册的Service
    bindService(intent, connection, Context.BIND_AUTO_CREATE);
}


private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.e(TAG, "onServiceConnected: success");
        iMyAidl = IMyAidl.Stub.asInterface(service);// proxy
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.e(TAG, "onServiceDisconnected: success");
        iMyAidl = null;
    }
};

@Override
protected void onDestroy() {
    super.onDestroy();
    unbindService(connection);

asInterface区分是跨进程还是不跨进程,得到AIDL,客户端申请操作

image.png

2、Service服务端代码

代码架构里两个AIDL类与客户端一致,多个Service类,这个Service类必须是按照包名规定跟客户端client 中的bindService一致

image.png

其他代码一致,看下Service代码

public class MyAidlService extends Service {

    private ArrayList<Person> persons;

    @Override
    public IBinder onBind(Intent intent) {
        persons = new ArrayList<>();
        Log.e("xjz111", "success onBind");
        return iBinder;//返回一个Binder处理
    }

    private IBinder iBinder = new IMyAidl.Stub() {
        @Override
        public void addPerson(Person person) throws RemoteException {
            Log.i("xjz111","服务端给你添加了一个Person");
            persons.add(person);
        }

        @Override
        public List<Person> getPersonList() throws RemoteException {
            Log.i("xjz111","服务端给你返回一个PersonList");
            return persons;
        }

        @Override
        public void setData(byte[] data) throws RemoteException {

        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("xjz111", "onCreate: success");
    }
}

看下运行结果

image.png

可以看到已经成功实现了两个进程间的简单通信

AIDL解析

看完使用,发现很简单,但是AIDL在其中到底做了什么工作呢?

image.png

可以看到,在build里,根据我们定义的方法,生成了对应的方法体,和Stub

IMyAIDL:就是两个进程间交互的通信协议,协议必须一致。

看看stub类里生成了啥 image.png

Proxy:给client客户端使用,里面会实现具体需要操作的方法

image.png

asInterface():返回代理对象,区分跨进程还是不跨进程

asInterface拿到对象后,返回一个aidl对象,去调用addPerson代码

image.png

看下其中生成的addPerson()怎么实现的

@Override public void addPerson(com.enjoy.service.Person person) 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 ((person!=null)) {
      _data.writeInt(1);
      person.writeToParcel(_data, 0);
    }
    else {
      _data.writeInt(0);
    }
    //最后transact()给Binder
    boolean _status = mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
    if (!_status && getDefaultImpl() != null) {
      getDefaultImpl().addPerson(person);
      return;
    }
    _reply.readException();
  }
  finally {
    _reply.recycle();
    _data.recycle();
  }
}

可以看到,addPerson()开始就用了两个数据包接收,通过 mRemote.transact()告诉Binder需要调什么方法,就是这个方法,让客户端跑到了服务端里去。

调方法的流程:

static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_setData = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);

给定义的方法标记初始值+1,2,3,4 最终通过flag找到要执行的方法

mRemote.transact()回调到服务端使用的onTransact()进行添加人员,数据返回的处理

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
  java.lang.String descriptor = DESCRIPTOR;
  switch (code)//根据传递的方法flag决定去执行哪个方法
  {
    case INTERFACE_TRANSACTION:
    {
      reply.writeString(descriptor);
      return true;
    }
    case TRANSACTION_addPerson:
    {
      data.enforceInterface(descriptor);
      com.enjoy.service.Person _arg0;
      if ((0!=data.readInt())) {
        _arg0 = com.enjoy.service.Person.CREATOR.createFromParcel(data);
      }
      else {
        _arg0 = null;
      }
      this.addPerson(_arg0);
      reply.writeNoException();
      return true;
    }
    case TRANSACTION_getPersonList:
    {
      data.enforceInterface(descriptor);
      java.util.List<com.enjoy.service.Person> _result = this.getPersonList();
      reply.writeNoException();
      reply.writeTypedList(_result);
      return true;
    }
    case TRANSACTION_setData:
    {
      data.enforceInterface(descriptor);
      byte[] _arg0;
      _arg0 = data.createByteArray();
      this.setData(_arg0);
      reply.writeNoException();
      return true;
    }
    default:
    {
      return super.onTransact(code, data, reply, flags);
    }
  }
}

Binder通过这个方法,让客户端发送时,传递方法的flag,在服务端调用onTransact()对执行完的数据进行操作返回,reply.writeTypedList(_result)代码意思就是把结果写到reply包(上面说的服务端返回给客户端的包)。