AIDL的概念
AIDL:全称是Android Interface Definition Language(Android接口定义语言)。它主要用在Android进程间通信中,Android中有一种进程间通信方式是Binder,AIDL就是帮我们自动生成了Binder相关代码,不需要我们自己去手动书写复杂的Binder类,我们只需要在AIDL接口文件中书写自己的调用远程服务的业务方法就可以了,大大简化了开发过程。
AIDL支持的数据类型
- 八种基本数据类型:byte、char、short、int、long、float、double、boolean
- String,CharSequence
- 实现了Parcelable接口的数据类型
- List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
- Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
AIDL使用步骤
例子源自《Android开发艺术探索》,点击获取Demo
Server端
1.首先创建一个Book类和两个aidl文件
class Book : Parcelable {
var bookId: Int
var bookName: String?
constructor(bookId: Int, bookName: String?) {
this.bookId = bookId
this.bookName = bookName
}
override fun describeContents(): Int {
return 0
}
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeInt(bookId)
dest.writeString(bookName)
}
constructor(source: Parcel) {
bookId = source.readInt()
bookName = source.readString()
}
override fun toString(): String {
return "Book{" +
"bookId=" + bookId +
", bookName='" + bookName + '\'' +
'}'
}
companion object CREATOR : Parcelable.Creator {
override fun createFromParcel(parcel: Parcel): Book {
return Book(parcel)
}
override fun newArray(size: Int): Array {
return arrayOfNulls(size)
}
}
}
Book.aidl文件
// Book.aidl
package com.example.helloaidl;
parcelable Book;
IBookManager.aidl文件
// IBookManager.aidl
package com.example.helloaidl;
import com.example.helloaidl.Book;
interface IBookManager {
// 获取图书列表
List getBookList();
//添加图书
void addBook(in Book book);
}
2.rebuild项目,会自动生成一个 IBookManager的java类, 里面书写了Binder相关代码。
public interface IBookManager extends android.os.IInterface
{
/** Default implementation for IBookManager. */
public static class Default implements com.example.helloaidl.IBookManager
{
// 获取图书列表
@Override public java.util.List getBookList() throws android.os.RemoteException
{
return null;
}
//添加图书
@Override public void addBook(com.example.helloaidl.Book book) throws android.os.RemoteException
{
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.helloaidl.IBookManager
{
private static final java.lang.String DESCRIPTOR = "com.example.helloaidl.IBookManager";
/**
* Stub构造函数
*/
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* 将IBinder 转换为BookManagerService interface
*/
public static com.example.helloaidl.IBookManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.helloaidl.IBookManager))) {
return ((com.example.helloaidl.IBookManager)iin);
}
return new com.example.helloaidl.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
{
java.lang.String descriptor = DESCRIPTOR;
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.example.helloaidl.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.helloaidl.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
/**
* 代理
*/
private static class Proxy implements com.example.helloaidl.IBookManager
{
private android.os.IBinder mRemote;
/**
* Proxy构造函数
*/
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);
boolean _status = mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getBookList();
}
_reply.readException();
_result = _reply.createTypedArrayList(com.example.helloaidl.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
//添加图书
@Override public void addBook(com.example.helloaidl.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);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addBook(book);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public static com.example.helloaidl.IBookManager sDefaultImpl;
}
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 static boolean setDefaultImpl(com.example.helloaidl.IBookManager impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.example.helloaidl.IBookManager getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
// 鑾峰彇鍥句功鍒楄〃
public java.util.List getBookList() throws android.os.RemoteException;
//娣诲姞鍥句功
public void addBook(com.example.helloaidl.Book book) throws android.os.RemoteException;
}
3.编写远程服务代码 BookManagerService,为了演示进程间的通信机制,故需要将Service与Activity处于不同的进程,需要在AndroidManifest.xml中,把service配置成android:process=":remote"
class BookManagerService : Service() {
private val TAG = BookManagerService::class.java.simpleName
//使用CopyOnWriteArrayList来支持并发读写
private val mBookList = CopyOnWriteArrayList()
override fun onBind(intent: Intent): IBinder? {
return mBinder
}
private val mBinder = object : IBookManager.Stub() {
override fun addBook(book: Book) {
mBookList.add(book)
}
override fun getBookList(): List {
return mBookList
}
}
}
客户端
创建Activity,在manifest中注册,完整代码如下:
class BookManagerActivity : AppCompatActivity() {
private val TAG = BookManagerActivity::class.java.simpleName
private var mRemoteBookManager: IBookManager? = null
private var boookId = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bindService()
initListener()
}
//绑定远程服务端
private fun bindService() {
val intent = Intent(this, BookManagerService::class.java)
intent.setPackage(packageName)
bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
}
//注册按钮监听,调用远程耗时方法需要开启线程
private fun initListener() {
btnGetBookList.setOnClickListener {
Toast.makeText(this, "GetBookList", Toast.LENGTH_SHORT).show()
Thread {
try {
mRemoteBookManager?.let { mRemoteBookManager ->
val list = mRemoteBookManager.bookList
Log.i(TAG, "query book list: $list")
}
} catch (e: RemoteException) {
e.printStackTrace()
}
}.start()
}
btnAddBook.setOnClickListener {
Toast.makeText(this, "AddBook", Toast.LENGTH_SHORT).show()
Thread {
try {
mRemoteBookManager?.apply {
val newBook = Book( boookId++, "Book$boookId")
Log.i(TAG, "add book: $newBook")
addBook(newBook)
}
} catch (e: RemoteException) {
e.printStackTrace()
}
}.start()
}
}
override fun onDestroy() {
unBindService()
super.onDestroy()
}
private fun unBindService() {
unbindService(mConnection)
}
//服务端连接状态回调
private var mConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.e(TAG, "onServiceConnected: $mRemoteBookManager")
//将服务端返回的Binder对象转换为aidl对象
mRemoteBookManager = IBookManager.Stub.asInterface(service)
Log.e(TAG, "onServiceConnected: $mRemoteBookManager")
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.i(TAG, "onServiceDisconnected ThreadName: ${Thread.currentThread().name}")
mRemoteBookManager = null
}
}
}
点击获取Demo