AIDL:全称是Android Interface Definition Language(Android接口定义语言)。它主要用在Android进程间通信中,Android中有一种进程间通信方式是Binder,AIDL就是帮我们自动生成了Binder相关代码,不需要我们自己去手动书写复杂的Binder类,我们只需要在AIDL接口文件中书写自己的调用远程服务的业务方法就可以了,大大简化了开发过程。当然,AIDL不是Binder通信所必须的,我们也可以不使用AIDL而自己去书写Binder代码。
上面介绍了AIDL的概念、作用、所支持的类型,那么下面开始写一个例子,看一下AIDL到底是怎么使用的,该例子就用刚哥的图书管理的那个场景(《Android开发艺术探索》第2章),实现的功能是两个独立的应用,一个是Client端,一个是Server端,Server端提供获取图书列表和添加图书两个功能,而Client通过和Server端的进程间通信在Client端操作那两个功能。
Book.java类,需要实现Parcelable接口(为了被AIDL所支持):
package com.znh.aidl.server;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by znh on 2018/6/10.
*
* 封装图书信息的Book类
*/
public class Book implements Parcelable {
//图书ID
public int bookId;
//图书名称
public String bookName;
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
private Book(Parcel source) {
bookId = source.readInt();
bookName = source.readString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
dest.writeString(bookName);
}
public static Creator CREATOR = new Creator() {
@Override
public Book createFromParcel(Parcel source) {
return new Book(source);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public String toString() {
return "Book{" +
"bookId=" + bookId +
", bookName='" + bookName + '\'' +
'}';
}
}
Book.aidl文件,需要声明一下:
// Book.aidl
package com.znh.aidl.server;
parcelable Book;
IBookManager.aidl文件:
// IBookManager.aidl
package com.znh.aidl.server;
import com.znh.aidl.server.Book;
interface IBookManager {
/**
* 获取图书列表
*/
List getBookList();
/**
* 添加图书
*/
void addBook(in Book book);
}
2、 步骤2:编译server端代码,会自动生成一个 IBookManager的java类, 里面书写了Binder相关代码。
IBookManager.java类,代码是系统自动生成的:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: E:\\Studiospace\\AidlDemo\\server\\src\\main\\aidl\\com\\znh\\aidl\\server\\IBookManager.aidl
*/
package com.znh.aidl.server;
public interface IBookManager extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.znh.aidl.server.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.znh.aidl.server.IBookManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.znh.aidl.server.IBookManager interface,
* generating a proxy if needed.
*/
public static com.znh.aidl.server.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.znh.aidl.server.IBookManager))) {
return ((com.znh.aidl.server.IBookManager) iin);
}
return new com.znh.aidl.server.IBookManager.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_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.znh.aidl.server.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.znh.aidl.server.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.znh.aidl.server.IBookManager {
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;
}
/**
* 获取图书列表
*/
@Override
public java.util.List getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.znh.aidl.server.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* 添加图书
*/
@Override
public void addBook(com.znh.aidl.server.Book book) 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 ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/**
* 获取图书列表
*/
public java.util.List getBookList() throws android.os.RemoteException;
/**
* 添加图书
*/
public void addBook(com.znh.aidl.server.Book book) throws android.os.RemoteException;
}
3、步骤3:编写远程服务代码RemoteService:
package com.znh.aidl.server;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by znh on 2018/6/10.
*
* 远程服务
*/
public class RemoteService extends Service {
//图书列表
private List mBookList;
@Override
public IBinder onBind(Intent intent) {
return new LocalBinder();
}
@Override
public void onCreate() {
super.onCreate();
mBookList = new ArrayList<>();
}
/**
* 编写远程服务中的本地Binder
*/
private class LocalBinder extends IBookManager.Stub {
@Override
public List getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
}
}
4、在server端的清单文件中注册该服务:
5、经过以上4步,服务端代码就编写完毕了,接下来,把服务端的aidl包连同它下面的文件都拷贝到客户端,aidl文件的包名不能变,要和服务端保持一致:
6、在Client的MainActivity中绑定远程服务,并调用远程服务中的方法实现功能:
package com.znh.aidl.client;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.znh.aidl.server.Book;
import com.znh.aidl.server.IBookManager;
import java.util.List;
/**
* Created by znh on 2018/6/10.
*
* 本地调用
*/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//远程服务Binder的代理
private IBookManager mIBookManager;
//创建连接
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取远程服务Binder的代理
mIBookManager = IBookManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
/**
* 绑定服务
*
* @param view
*/
public void bindService(View view) {
Intent intent = new Intent();
intent.setAction("com.znh.aidl.server.remoteservice");
intent.setPackage("com.znh.aidl.server");
startService(intent);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
/**
* 添加图书
*
* @param view
*/
public void addBook(View view) {
try {
mIBookManager.addBook(new Book(1, "Android"));
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
* 获取图书列表
*
* @param view
*/
public void getBookList(View view) {
try {
List books = mIBookManager.getBookList();
Log.e("znh", "books:" + books.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}