AIDL简介
AIDL (Android Interface Definition Language)是Android内部进程通信(IPC)的接口定义语言,通过它可以定义客户端与服务器端的通信接口,实现跨进程通信。
我的理解就是:Android中的AIDL就是对使用Binder进行进程间通信过程的封装,只需要定义好接口,服务端实现接口,客户端获得Binder代理对象,直接调用服务,中间发送数据,接受数据,处理数据 统统有AIDL完成。
非AIDL实现Binder进程间通信
Binder机制
Binder服务分为两种,一种是实名服务、一种是匿名服务。
实名服务是指Binder在ServiceManager中注册过,可以通过名字查询到该Binder。可以通过ServiceManager.addService(“服务名”)添加服务,ServiceManager.getService(“服务名”)查询服务。要使用ServiceManager得先获得系统开发权限。
匿名服务就是没有在ServiceManager注册过的Binder。通过bindService方法,建立binder通信。
一个远程对象的基接口,是为高性能而设计的轻量级远程调用机制的核心部分,它不仅用于远程调用,也可以用于进程内调用。这个接口描述了与远程对象进行交互的抽象协议。建议继承Binder类,而不是直接实现这个接口。
IBinder的主要API是transact(),与它对应另一个方法是Binder.onTransact。第一个方法使你可以向远端的IBinder对象发送调用,第二个方法使你自己的远程对象能够响应接收到的调用。IBinder的API都是同步执行的,比如transact()直到对方的Binder.onTransact()方法调用完成后才返回。而在跨进程的时候,在IPC的帮助下,也是同样的效果。
通过transact()发送的数据是Parcel,Parcel是一种一般的缓冲区,除了有数据外还带有一些描述它内容的元数据。元数据用于管理IBinder对象的引用,这样就能在缓冲去从一个进程移动到另一个进程时,保存这些引用。这样就保证了当一个IBinder被写入到Parcel并发送到另一个进程中,如果另一个进程把同一个IBinder的引用回发到原来的进程,那么这个原来的进程就能接收到发出的那个IBinder的引用。这种机制使IBinder和Binder像唯一标志符那样在进程间管理。
下面用一个demo来说明:
Server端
package com.demo.binderdemo;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
public class MyService extends Service {
public static final int TRANSACTION= 0x001;
private ServerBinder mBinder=new ServerBinder();
//这里可以简单理解为将可以被其他进程调用的对象告知系统。
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//进程Binder类,Binder类本身已经实现了IBinder接口
//这样ServerBinder的对象就可以通过Binder机制被其他进程访问。
private class ServerBinder extends Binder{
//onTransact会被Binder的transact调用
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code){
case TRANSACTION:{
int num;
num = data.readInt();//读取data中的数据
num++;
reply.writeNoException();
reply.writeInt(num);将数据写入reply
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
}
}
新建一个Servcie,在Service定义ServerBinder内部类,继承Binder,Binder是Android为我们实现好的Binder本地对象的一个基类,通过继承这个类,实现自己不同的服务。其中onTransact方法是用来接受Client端发送的请求和数据,并将处理后的数据返回给Client。
同时在AndroidManifest.xml中将MyService设置为远程进程。
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"
android:process=":remote" ></service>
再来看Client
package com.demo.binderdemo;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import static com.demo.binderdemo.MyService.TRANSACTION;
public class MainActivity extends Activity {
private TextView tv_binder;
private IBinder clientBinder;
private ServiceConnection connection= new ServiceConnection() {
//当客户端与服务端建立通信成功时,将回调onServiceConnected
/**
* 接收服务端Binder对象的代理对象BinderProxy;
* @param name
* @param service
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取服务端Binder对象的代理对象BinderProxy
clientBinder=service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_binder= (TextView) findViewById(R.id.tv_binder);
Intent bindIntent=new Intent(this,MyService.class);
bindService(bindIntent,connection,BIND_AUTO_CREATE);//绑定服务,建立服务端与客户端的通信
Button btn_binder= (Button) findViewById(R.id.btn_binder);
btn_binder.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
GetData();
}
});
}
private void GetData(){
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
int _result;
_data.writeInt(Integer.decode(tv_binder.getText().toString()));//将数据存入_data
//向服务端发送数据
clientBinder.transact(TRANSACTION,_data, _reply, 0);
_reply.readException();
_result = _reply.readInt();//获取服务端的返回数据
tv_binder.setText(_result+"");
} catch (RemoteException e) {
e.printStackTrace();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
}
实现ServiceConnection接口,在onServiceConnected方法中获取ServerBinder的代理对象,调用bindService,建立Binder通信。
GetData方法是通过Binder代理对象,向服务端发送数据,并接受服务端的返回数据。
从上述代码中可以看出,在Client端我们需要准备数据、发送数据、接受Server端返回的数据,Server端我们需要接受数据、处理数据、返回给Client端数据,虽然很简单,但是如果Server端提供的服务有很多,写起来还是很麻烦,AIDL对上述过程进程的封装,我们只需要在Server端实现服务,Client获取Binder代理对象后,直接调用就可以了,中间数据处理 数据发送、数据接受的过程就不需要管了。
下面用一个银行办理业务的Demo来说明
以Android Studio为例
第一步新建AIDL接口
File–>New–>AIDL–>AIDL File
// IBankAIDL.aidl
package com.demo.binderdemoaidl;
// Declare any non-default types here with import statements
interface IBankAIDL {
//开户
String openAcount(String name,String password);
//存钱
String saveMoney(int money,String account);
//取钱
String takeMoney(int money,String account,String password);
//销户
String closeAccount(String account,String password);
}
然后Build–>Make Project
在此目录下会生成IBankAIDL.Java文件
UML图如下:
Stub是一个抽象类继承了Binder类和IBankAIDL接口
Proxy是Stub中的内部类,主要是用来对Binder代理对象进行装饰
先来看一下Proxy
private static class Proxy implements com.demo.binderdemoaidl.IBankAIDL {
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.lang.String openAcount(java.lang.String name, java.lang.String password) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
_data.writeString(password);
mRemote.transact(Stub.TRANSACTION_openAcount, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
//存钱
@Override
public java.lang.String saveMoney(int money, java.lang.String account) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(money);
_data.writeString(account);
mRemote.transact(Stub.TRANSACTION_saveMoney, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
//取钱
@Override
public java.lang.String takeMoney(int money, java.lang.String account, java.lang.String password) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(money);
_data.writeString(account);
_data.writeString(password);
mRemote.transact(Stub.TRANSACTION_takeMoney, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
//销户
@Override
public java.lang.String closeAccount(java.lang.String account, java.lang.String password) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(account);
_data.writeString(password);
mRemote.transact(Stub.TRANSACTION_closeAccount, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
Proxy继承了IBankAIDL接口并实现了具体的方法
Proxy中的成员变量mRemote是Binder的代理对象,通过代理对象就可以和服务端进程通信,通信的过程封装在了每个方法中,不需要我们自己再去写。
再来看Stub,其有三个方法
asInterface方法
public static com.demo.binderdemoaidl.IBankAIDL asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.demo.binderdemoaidl.IBankAIDL))) {
return ((com.demo.binderdemoaidl.IBankAIDL) iin);
}
return new com.demo.binderdemoaidl.IBankAIDL.Stub.Proxy(obj);
}
asInterface这个方法就是将获得的Binder代理对象使用Proxy类进程包装一下,Proxy使用这个Binder代理对象向Server端发送数据。
asBinder方法
@Override
public android.os.IBinder asBinder() {
return this;
}
这个方法很简单,返回当前的Binder本地对象。
onTransact方法
@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_openAcount: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _result = this.openAcount(_arg0, _arg1);
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_saveMoney: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _result = this.saveMoney(_arg0, _arg1);
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_takeMoney: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
java.lang.String _result = this.takeMoney(_arg0, _arg1, _arg2);
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_closeAccount: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _result = this.closeAccount(_arg0, _arg1);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
这个方法前面介绍过,是用来接受服务端发送过来的数据、处理数据、返回数据的,这个过程也被封装到了AIDL中。
以上三个方法是实现好的,使用Stub时,只需实现IBankAIDL接口的函数即可。
下面来看一下如何使用:
Server端:
新建BankService,并设置为远程服务
package com.demo.binderdemoaidl;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class BankService extends Service {
@Override
public IBinder onBind(Intent intent) {
return new BankBinder();
}
public class BankBinder extends IBankAIDL.Stub {
private int total=0;
/**
* 开户
* @param name 户主名字
* @param password 密码
* @return 开户信息
* @throws RemoteException
*/
@Override
public String openAcount(String name, String password) throws RemoteException {
return name+"开户成功!账号为:"+ "6354726354627";
}
/**
* 存钱
* @param money 金额
* @param account 账户
* @return 存钱信息
* @throws RemoteException
*/
@Override
public String saveMoney(int money, String account) throws RemoteException {
total=total+money;
return "账户:"+account+" 存入"+money+"单位:人民币"+" 余额:"+total+"单位:人民币";
}
/**
* 取钱
* @param money 取钱信息
* @param account 账户
* @param password 密码
* @return
* @throws RemoteException
*/
@Override
public String takeMoney(int money, String account, String password) throws RemoteException {
total= total-money;
return "账户:"+account+"支取"+money+"单位:人民币"+" 余额:"+total+"单位:人民币";
}
/**
* 销户
* @param account 账户
* @param password 密码
* @return 销户信息
* @throws RemoteException
*/
@Override
public String closeAccount(String account, String password) throws RemoteException {
return account+"销户成功";
}
}
}
在BankService中新建一个内部类,继承IBankAIDL.Stub接口,并实现IBankAIDL接口的方法
Client端:
package com.demo.binderdemoaidl;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity implements View.OnClickListener{
private IBankAIDL mBankBinder;
private TextView tv_binder;
private ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBankBinder=IBankAIDL.Stub.asInterface(service);
Log.i("ComponentName",name+"");
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//绑定Service
bindService(new Intent(this,BankService.class),conn,BIND_AUTO_CREATE);
tv_binder= (TextView) findViewById(R.id.tv_binder);
init(R.id.aidl_bank_open_btn);
init(R.id.aidl_bank_save_btn);
init(R.id.aidl_bank_take_btn);
init(R.id.aidl_bank_close_btn);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
private void init(int resID){
Button b= (Button) findViewById(resID);
b.setOnClickListener(this);
}
@Override
public void onClick(View v) {
try{
switch (v.getId()){
case R.id.aidl_bank_open_btn:
tv_binder.setText(mBankBinder.openAcount("小文","123456"));
break;
case R.id.aidl_bank_save_btn:
tv_binder.setText(mBankBinder.saveMoney(2000,"6354726354627"));
break;
case R.id.aidl_bank_take_btn:
tv_binder.setText(mBankBinder.takeMoney(1000,"6354726354627","123456"));
break;
case R.id.aidl_bank_close_btn:
tv_binder.setText(mBankBinder.closeAccount("6354726354627","123456"));
break;
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
在onServiceConnected中获取Binder代理对象并调用IBankAIDL.Stub.asInterface方法对Binder代理对象进行包装得到mBankBinder,通过bindService建立binder通信,这样就可以使用mBankBinder与Server端BankBinder进程通信。
UML图: