AIDL
AIDL 即安卓接口定义语言,其语法类似 java,用于定义一些特殊的接口。
由来
就以 service 为例:
android 常以 service 提供一些服务和数据,acticity 通过 binder 与service 进行数据交换(如 get 和 set )。然而,有时候 acticity 需要访问远程的 service (如别的应用程序提供的 service),之前的方案就不再适用。为了解决这种跨进程通信的需求,android 引入了 AIDL 机制。
使用
说明
由于安卓中不同进程的内存是不共享的,在 onBind() 中我们不再像原来那样返回 Binder 的子类,而是返回 AIDL 的接口类。
这里给的例子是 C- S 模式,Server 和 Client 是两个不同的 app,不能共享内存。
Server 端运行一个 Service 播放音乐,对外提供 AIDL 接口 play() 和 pause();
Client 端通过调用它来和 Service 交互(控制音乐)。
服务端 server
- 新建一个 .aidl 文件(IMusicService.aidl),定义一些访问 service 的接口,如 get,set,或者别的什么操作:
// IMusicService.aidl
package com.example.i_jinliangshan.aidl_server;
// Declare any non-default types here with import statements
import com.example.i_jinliangshan.aidl_server.Music;
interface IMusicService {
void play();
void pause();
Music getMusic(); //对于自定义类,还得进行序列化
}
编译一下 app (build -> make),编译器会自动生成对应的 IMusicService.java,
也就是 java 版本的接口。
在 Service 中,弄一个类实现这个接口,并在 onBind 中返回。
// Stub 是编译器自动生成的,点进去可以看到,它 implements 了 IMusicService 的接口
public class AIDLBinder extends IMusicService.Stub {
@Override
public void play() throws RemoteException {
MusicService.this.play();
}
@Override
public void pause() throws RemoteException {
MusicService.this.pause();
}
@Override
public Music getMusic() throws RemoteException {
return music;
}
}
//--------------------------
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
String mod = intent.getStringExtra("bind_mod");
Log.d("intent mod:", mod);
if(mod.equals("local"))
return new LocalBinder(); // 这个 LocalBinder 是原来的方式
else if(mod.equals("remote"))
return new AIDLBinder(); // AIDL 的方式
return null;
}
客户端 Client
由于 Client 在另一个 app 里,必须将 Server 端定义的 AIDL 接口统统复制过来,才能使用。
- 用隐式 intent 的方式绑定服务端的 service,在 onServiceConnected() 中获取 AIDL 接口实例
// 绑定 service
// 服务端 AndroidManifest.xml 中的 intent-filter action 声明的字符串
public static final String ACTION = "com.example.i_jinliangshan.aidl_server.MusicService";
@Override
protected void onStart() {
super.onStart();
intent = new Intent(ACTION);
intent.putExtra("bind_mod", "remote");
bindService(intent, sc, BIND_AUTO_CREATE);
}
// 获取 binder
private IMusicService binder;
private ServiceConnection sc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
binder = IMusicService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
- 用 binder.play() 和 binder.pause() 控制远程的音乐播放服务。
总结
总的来说,AIDL 以面向接口的方式实现了跨进程调用的需求,客户端和服务端各司其职,有利于模块间的分离。
PS:AIDL 默认的是同步调用,如果调用 Server 端的耗时任务,不应在 Client 端的 UI 线程中,而应另起一个线程。