我们经常在android开发中会接触到aidl这个跨进程服务组件,今天我就写点关于对它的理解。
首先,aidl是典型的代理模式。那自然它有调用的一端以及实现的一端,暂且先定义为,API.Proxy以及API_Stub我们不考虑其内部的实现原理,
因为android在里面都已经封装好了数据的实现原理。
接下来我们直接根据一个音乐播放器的代码直观的来说:首先是我们的主角,aidl文件,实际上只是一个接口类。只要你定义一个类,后缀名aidl你就会发现,gen文件下会自动生成相应地文件。
interface IMediaService {
boolean play(int pos);
boolean playById(int id);
boolean rePlay();
boolean pause();
boolean prev();
boolean next();
int duration();
int position();
boolean seekTo(int progress);
void refreshMusicList(in List<MusicInfo> musicList);
void getMusicList(out List<MusicInfo> musicList);
int getPlayState();
int getPlayMode();
void setPlayMode(int mode);
void sendPlayStateBrocast();
void exit();
int getCurMusicId();
void updateNotification(in Bitmap bitmap, String title, String name);
void cancelNotification();
MusicInfo getCurMusic();
}
然后就是调用者这边:
private void initConnection() {
mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IMediaService.Stub.asInterface(service);//在界面组件和服务组件绑定的流程中,
界面组件可以通过Context.bindService获得IBinder的对象,
通过它的静态方法asInterfacce可以获得API_Proxy的对象实例,然后就可以通过这个实例实现对服务端的远程调用。
if (mService != null) {
try {
mService.getMusicList(mMusicList);//
mCurMusicId = mService.getCurMusicId();
mPlayingSongPosition = MusicUtils.seekPosInListById(
mMusicList, mCurMusicId);
mPlayState = mService.getPlayState();
initListView();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
};
Intent intent = new Intent("com.sc.music.service.MediaService");//指定服务的位置,哪个包下的类。
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);//绑定服务
}
最后就是在service中对aidl接口中的方法的实现。这是从MediaService中摘取的实现的主要代码。
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IBinder mBinder = new ServerStub();//这是获取IBinder对象
private class ServerStub extends IMediaService.Stub {//这个类就是继承API_Stub,实现Implement类型,在里面填充执行的代码即可,
//无需关注其它的底层通信细节,这大大提高了效率,降低了开发成本。
@Override
public boolean pause() throws RemoteException {
// MediaService.this.stopForeground(true);
return mMc.pause();
}
@Override
public boolean prev() throws RemoteException {
return mMc.prev();
}
@Override
public boolean next() throws RemoteException {
return mMc.next();
}
@Override
public boolean play(int pos) throws RemoteException {
return mMc.play(pos);
}
@Override
public int duration() throws RemoteException {
return mMc.duration();
}
@Override
public int position() throws RemoteException {
return mMc.position();
}
@Override
public boolean seekTo(int progress) throws RemoteException {
return mMc.seekTo(progress);
}
@Override
public void refreshMusicList(List<MusicInfo> musicList) throws RemoteException {
mMc.refreshMusicList(musicList);
}
@Override
public void getMusicList(List<MusicInfo> musicList) throws RemoteException {
List<MusicInfo> music = mMc.getMusicList();
for (MusicInfo m : music) {
musicList.add(m);
}
}
@Override
public int getPlayState() throws RemoteException {
return mMc.getPlayState();
}
@Override
public int getPlayMode() throws RemoteException {
return mMc.getPlayMode();
}
@Override
public void setPlayMode(int mode) throws RemoteException {
mMc.setPlayMode(mode);
}
@Override
public void sendPlayStateBrocast() throws RemoteException {
mMc.sendBroadCast();
}
@Override
public void exit() throws RemoteException {
cancelNotification();
stopSelf();
mMc.exit();
}
@Override
public boolean rePlay() throws RemoteException {
return mMc.replay();
}
@Override
public int getCurMusicId() throws RemoteException {
return mMc.getCurMusicId();
}
@Override
public void updateNotification(Bitmap bitmap, String title, String name)
throws RemoteException {
MediaService.this.updateNotification(bitmap, title, name);
}
@Override
public void cancelNotification() throws RemoteException {
MediaService.this.cancelNotification();
}
@Override
public boolean playById(int id) throws RemoteException {
return mMc.playById(id);
}
@Override
public MusicInfo getCurMusic() throws RemoteException {
return mMc.getCurMusic();
}
}