1.AIDL介绍
Android系统中,进程之间不能共享内存,因此需要提供一些机制在不同进程之间进行数据通信,为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。我们知道4个Android应用程序组件中的3个(Activity、BroadcastReceiver和ContentProvider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。
2.AIDL使用步骤
AIDL是不同进程间进行操作,我们需要两个项目,一个服务端,一个客户端。服务端实现一个播放器后台Service,实现播放控制功能,比如播放、暂停、恢复、停止等。客户端是一个Activity,显示用户界面,并通过AIDL与服务端交互,完成播放控制功能。具体步骤如下:
2.1 服务端步骤
2.1.1 创建AIDL文件
在服务端工程中新建一个AIDL文件,IPlayer.aidl,文件内容如下:
interface IPlayer {
int play(String url, int position);
int pause();
int resume();
int seek(int position);
int setScale(int scale);
}
在这个文件中定义接口,这个接口是对客户端提供服务的接口,可以根据需要修改。保存后,Eclipse的ADT插件会自动把AIDL文件编译成java代码,生成在gen目录下,文件名是IPlayer.aidl。
2.1.2 实现AIDL接口中的方法
新建 一个类,继承自动生成的IPlayer.java中的内部抽象类Stub,实现AIDL接口中方法。例如PlayerImpl.java,文件内容如下:
public class PlayerImpl extends Stub {
private static final String TAG = "PlayerImpl";
@Override
public int play(String url, int position) throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "play: url=" + url + ",position=" + position);
return 0;
}
@Override
public int pause() throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "pause!!!");
return 0;
}
@Override
public int resume() throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "resume!!!");
return 0;
}
@Override
public int seek(int position) throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "seek: position=" + position);
return 0;
}
@Override
public int setScale(int scale) throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "setScale: scale=" + scale);
return 0;
}
}
2.1.3 建立一个服务类
AIDL是通过Service的IBinder对象对外提供服务的,因此我们需要实现一个Service,在onBind函数中返回一个IBinder对象,自动生成的IPlayer.java中的Stub继承自IBinder,代码如下:
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.receivebroadcast.IPlayer
而上一步中新建的PlayerImpl类又继承自Stub,因此在onBind函数中直接返回PlayerImpl即可。新建一个PlayerService类,继承自Service,代码如下:
public class PlayerService extends Service {
private Stub iPlayer = new PlayerImpl();
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
Toast.makeText(this, "ReceiveBroadcast onBind!!!", Toast.LENGTH_SHORT).show();
return iPlayer;
}
}
至此,服务端的工作已经全部完成。
2.2 客户端步骤
2.2.1复制AIDL文件
将服务端的AIDL文件复制到客户端,注意:AIDL文件中包名不能更改,必须是服务端AIDL文件的包名。
2.2.2Bind Service
创建一个ServiceConnection,在onServiceConnected()中获取Server端的IBinder接口。代码如下:
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iPlayer = IPlayer.Stub.asInterface(service);
}
};
在Activity启动的时候,比如onCreate()函数中调用bindService,代码如下:
Intent intent = new Intent();
intent.setAction(MY_SERVICE);
bindService(intent, conn, Service.BIND_AUTO_CREATE);
2.2.3 调用Server端AIDL中的接口
在需要与服务端通信时,调用onServiceConnected()中获取的IBinder接口中的方法,代码如下:
if (null != iPlayer) {
try {
Log.d(TAG, "Send request!!!");
iPlayer.play("http://163.com/1234.mp4", 30);
iPlayer.pause();
iPlayer.resume();
iPlayer.seek(20);
iPlayer.setScale(2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
3.总结
AIDL用于进程间通信,底层采用的是Android的Binder机制,效率很高,实测客户端发送请求的时间和服务端接收到请求的时间一致,基本没有延迟。另外客户端的请求是同步的,服务端返回结果之后函数才返回。
AIDL接口是自定义的,可以自定义函数名,参数等,使用比较灵活。