AIDL(Android Interface Definition Language):安卓接口描述语言。通常我们使用它来帮助我们完成进程间的通信。程序中的数据交换和通信其实都是内存之间的调用来完成的,但是不同的进程之间是不能访问相互之间的内存的,AIDL通过binder机制实现一条管道,客户端和服务端都去实现它,然后利用这个管道相互通信。类似于线程之间共享进程的内存来实现通信,进程则是通过将数据拆分成系统可识别的单元从而进行通信。
一.实现Service的服务端暴露接口进行通信。
要实现进程间的通信,首先作为服务端的应用进程要实现和客户端一样的接口并启动起来,等待客户端的接入。首先是AIDL文件的编写,这两个文件在各自的程序中,放置的包名要一样,程序的应用包名不能一样,否则会冲突,但是AIDL文件的包名要一样。
package com.example.aidlclient;
interface TestPrint{
void print();
}
以上就是整个AIDL文件的代码,一个包的声明和一个接口的定义,注意这个接口是不能添加public和private这些权限修饰词的。这个AIDL文件的名字是TestPrint.aidl,保存之后将在gen文件夹中对应的目录下自动生成java类。接下来就是Service类的编写,提供接口方法的。
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
Log.i("com.example.androidserver", "service create success") ;
}
@Override
public IBinder onBind(Intent arg0) {
return new MyBinder();
}
class MyBinder extends TestPrint.Stub {
@Override
public void print() throws RemoteException {
Log.i("com.example.androidserver", "return mybinder") ;
}
}
}
这个Service中最重要的就是onBind方法的返回了,客户端连接服务之后拿到这个binder对象进行其他操作,可以看到这个binder对象是继承自TestPrint.Stub类的,这个是AIDL文件自动生成的一个类,这个继承了binder接口,实现了TestPrint里面的接口,所以这个对象可以做onBind方法的返回值,又可以在客户端调用这个已经实现了TestPrint里面接口的方法。接下来就是客户端连接服务端了。
二.客户端:
在客户端里面可以创建一个跟服务端一样的包,并且把服务端里面的AIDL文件拷到客户端里面,客户端也将自动生成一份java类文件,在gen目录下,这时候我们只要启动服务端进程,客户端开启服务连接服务端的service:
class MyServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder binder) {
tp = TestPrint.Stub.asInterface(binder);
}
public void onServiceDisconnected(ComponentName name) {
}
}
以上是service连接的内部类,里面调用了TestPrint.Stub.asInterface(binder)方法将连接服务端之后返回的binder对象转化成一个TestPrint对象,我们连接服务端service成功之后就会调用这个方法,拿到这个对象。
msc = new MyServiceConnection();
intent = new Intent();
intent.setComponent(new ComponentName("com.example.androidserver",
"com.example.androidserver.MyService"));
bindService(intent, msc, Context.BIND_AUTO_CREATE);
通过以上代码之后,我们定义的全局变量tp就被赋值了,就可以调用服务端的方法了。
case R.id.print:
if (tp != null) {
try {
tp.print();
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;