AIDL简单描述
AIDL全称是:Android Interface Define Language
因此传递对象, 只能把对象拆分成操作系统能理解的简单形式, 以达到跨界对象访问的目的. 在J2EE中,采用RMI的方式, 可以通过序列化传递对象. 在Android中, 则采用AIDL的方式. 理论上AIDL可以传递Bundle,实际上做起来却比较麻烦。
AIDL(AndRoid接口描述语言)是一种借口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的。
如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象.AIDL的IPC的机制和COM或CORBA类似, 是基于接口的,但它是轻量级的。它使用代理类在客户端和实现层间传递值. 如果要使用AIDL, 需要完成2件事情:
1. 引入AIDL的相关类.;
2. 调用aidl产生的class.
AIDL实现进程间通信实战:
项目结构是:
在包名上点击右键新建.AIDL文件IMyAidlInterface.aidl,
package com.troy.aidldemo;
// Declare any non-default types here with import statements
interface IMyAidlInterface {//定义接口,两个方法;
int add(int arg1,int arg2);
int min(int arg1,int arg2);
}
然后Make Project,会自动生成对应的IMyAidlInterface.java文件,这个后续再分析。
服务端CalcService.java核心代码如下:
public class CalcService extends Service{
private static final String TAG = "server";
public void onCreate(){
Log.e(TAG, "onCreate");
}
public IBinder onBind(Intent t){
Log.e(TAG, "onBind");
return mBinder;
}
public boolean onUnbind(Intent intent){
Log.e(TAG, "onUnbind");
return super.onUnbind(intent);
}
public void onDestroy(){
Log.e(TAG, "onDestroy");
super.onDestroy();
}
private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub(){//IMyAidlInterface.Stub类是Binder的子类
@Override
public int add(int x, int y) throws RemoteException{//实现接口中的加法
return x + y;
}
@Override
public int min(int x, int y) throws RemoteException{//实现接口中的减法
return x - y;
}
};
}
并且需要在清单文件中对CalcService进行注册服务。
<service android:name=".CalcService"
android:process=".remote">
</service>
客户端代码MainActivity.java代码如下:
public class MainActivity extends AppCompatActivity {
/**
* 使用Binder实现通信(参见上一篇文章)
*/
private IBinder mPlusBinder;
/**
* 使用AIDL实现通信
*/
private IMyAidlInterface mCalcAidl;
private EditText et1,et2;
private int arg1,arg2;
private ServiceConnection mServiceConnPlus = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service){
Log.i("server", " onServiceConnected()");
//mPlusBinder = service;
mCalcAidl = IMyAidlInterface.Stub.asInterface(service);//
}
@Override
public void onServiceDisconnected(ComponentName name){
Log.i("server", "onServiceDisconnected()");
//mPlusBinder=null;
mCalcAidl=null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et1=(EditText)findViewById(R.id.et1);
et2=(EditText)findViewById(R.id.et2);
}
/**绑定服务*/
public void bindService(View view){
Intent intent = new Intent(this, CalcService.class);
boolean plus=bindService(intent, mServiceConnPlus, Context.BIND_AUTO_CREATE);
Toast.makeText(view.getContext(), "绑定服务"+plus, Toast.LENGTH_SHORT).show();
}
/**取消链接*/
public void unbindService(View view){
try {
unbindService(mServiceConnPlus);
//mPlusBinder=null;
Toast.makeText(view.getContext(), "解绑成功", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(view.getContext(), "未绑定", Toast.LENGTH_SHORT).show();
}
}
/**加法运算*/
public void add(View view) throws Exception{
if(!inspectData()){
return;
}
if (mCalcAidl != null){
int result = mCalcAidl.add(arg1, arg2);
Toast.makeText(this, result + "", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show();
}
}
/**减法运算*/
public void subtraction(View view) throws Exception{
if(!inspectData()){
return;
}
if (mCalcAidl != null){
int result = mCalcAidl.min(arg1, arg2);
Toast.makeText(this, result + "", Toast.LENGTH_SHORT).show();
} else{
Toast.makeText(this, "服务端未绑定或被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show();
}
}
/**检查数据*/
private boolean inspectData(){
//省略代码...
}
最后运行的结果如图:
原理简单分析
在服务端,我们调用AIDL接口的代码是:
private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub(){
@Override
public int add(int x, int y) throws RemoteException{
return x + y;
}
@Override
public int min(int x, int y) throws RemoteException{
return x - y;
}
};
再来系统看看我们写完AIDL文件之后,系统生成的java类是什么?我们找到generated文件夹下—>source—>aidl目录,如图所示:
找到IMyAidlInterface.java。先看看Stub静态类,Stub类IMyAidlInterface接口的静态抽象类,继承了Binder类,因此它是Binder的一个子类,同时实现了IMyAidlInterface接口。我们看看Stub类的定义:
public static abstract class Stub extends android.os.Binder implements com.troy.aidldemo.IMyAidlInterface
而IMyAidlInterface接口又是系统IInterface接口的子类:
public interface IMyAidlInterface extends android.os.IInterface
在客户端,我们实现了IMyAidlInterface接口的实例:
private IMyAidlInterface mCalcAidl;
@Override
public void onServiceConnected(ComponentName name, IBinder service){
Log.i("server", " onServiceConnected()");
//mPlusBinder = service;
mCalcAidl = IMyAidlInterface.Stub.asInterface(service);
}
其中调用了Stub抽象类的asInterface方法:
/**
* Cast an IBinder object into an com.troy.aidldemo.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.troy.aidldemo.IMyAidlInterface asInterface(android.os.IBinder obj){//该方法的作用是:将一个IBinder 对象转换成我们自定义的IMyAidlInterface 接口对象;
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.troy.aidldemo.IMyAidlInterface))) {
return ((com.troy.aidldemo.IMyAidlInterface)iin);
}
return new com.troy.aidldemo.IMyAidlInterface.Stub.Proxy(obj);
}
同时在生成的java类中还会自动生成一个Proxy的静态代理类:
private static class Proxy implements com.troy.aidldemo.IMyAidlInterface{
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;
}
//中间的加法运算--会调用Stub的真正加法
@Override
public int add(int arg1, int arg2) throws android.os.RemoteException{
//省略代码...
}
//中间的减法运算--会调用Stub的真正减法
@Override
public int min(int arg1, int arg2) throws android.os.RemoteException {
//省略代码...
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_min = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
我们来看看加法的运算流程到底是如何:
1 第一步
在客户端的EditText获取用户输入的参数,作非空判断:
/**检查数据*/
private EditText et1,et2;
private int arg1,arg2;
private boolean inspectData(){
if(TextUtils.isEmpty(et1.getText().toString())||TextUtils.isEmpty(et2.getText().toString())){
Toast.makeText(this, "请填全两个参数!", Toast.LENGTH_SHORT).show();
return false;
}
arg1=Integer.parseInt(et1.getText().toString());
arg2=Integer.parseInt(et2.getText().toString());
return true;
}
2 第二步
在客户端调用IMyAidlInterface的add方法:
int result = mCalcAidl.add(arg1, arg2);
3 第三步
会执行代理类Proxy的add方法:
private static class Proxy implements com.troy.aidldemo.IMyAidlInterface{
@Override
public int add(int arg1, int arg2) throws android.os.RemoteException{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(arg1);
_data.writeInt(arg2);
//mRemote就是一个IBinder对象
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
4 第四步
会调用Stub的add方法,代码如下:
@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_add:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
5 第五步
在服务端会回调mBinder 的add方法,这是真正实现加法运算的地方,:
private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub(){
@Override
public int add(int x, int y) throws RemoteException{
return x + y;
}
};
同理,减法运算的调用流程也是一样:
客户端参数-->Proxy代理类--->Stub类--->CalcService中的mBinder
AIDL中实现进程间通信的流程图分析为:
以上,就完成了使用AIDL来实现进程间的通信。
总结:
通过本DEMO需要掌握以下几点:
(1)如何写IMyAidlInterface.aidl文件,并能分析系统生成的IMyAidlInterface.java代码,理解其中的onTransact()方法;
(2)在服务端要实现IMyAidlInterface.Stub实例及接口方法,并理解Stub类与Binder类的关系。
(3)客户端与服务端的连接,bindService(intent, mServiceConnPlus, Context.BIND_AUTO_CREATE);
(4)在客户端实现IMyAidlInterface接口对象,并理解IMyAidlInterface.Stub.asInterface(service);