AIDL的Proxy-Stub理解:(以实际媒体播放器服务单独运行在一个进程中为例)
一、从接口定义入手1、定义AIDL接口 AudioPlayerAidl.aidl文件
interface AudioPlayerAidl { // 注意,这里不要使用public关键字 /* * 打开媒体,但不播放 * @param path 文件路径 */ int openMedia(String path);// 方便起见,仅定义一个接口函数 }
1、生成文件如下
public interface AudioPlayerAidl extends android.os.IInterface { // 内部Stub抽象类(实现AudioPlayerAidl接口) // 注意:该类是需要我们在服务端去继承并实现AudioPlayerAidl接口 public static abstract class Stub extends android.os.Binder implements AudioPlayerAidl { // Binder描述符 public static final java.lang.String DESCRIPTOR = "com.zhonghong.zhmedia.service.AudioPlayerAidl"; // 构造器 public Stub() { this.attachInterface(this, DESCRIPTOR);//Binder类中的一个函数 } // 供客户端调用的重要函数(获取远程调用接口) public static AudioPlayerAidl asInterface(IBinder ib) { if (ib == null) { return null; } // 在同一个进程时不会生成代理类 IInterface iin = ib.queryLocalInterface(DESCRIPTOR);//根据attachInterface中返回相应对象 if (iin != null && iin instanceof AudioPlayerAidl) { return ((AudioPlayerAidl) iin); } // 必要时生成代理类(跨进程通信时) return new AudioPlayerAidl.Stub.Proxy(ib); } @Override public IBinder asBinder() { return this; } // 该函数由父类transact调用 (根据code码确定调用哪个函数),接收来自客户端的请求 @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case INTERFACE_TRANSACTION: {//IBinder的一个通信协议常量 reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_openMedia: { data.enforceInterface(DESCRIPTOR); String path; path = data.readString(); // 注意,从这里调用到了在服务端实现的openMedia int _result = this.openMedia(path); reply.writeNoException(); reply.writeInt(result); return true; } } // 父类Binder处理 return super.onTransact(code, data, reply, flags); } // Stub的内部类Proxy private static class Proxy implements AudioPlayerAidl { // 服务端IBinder接口 private IBinder mRemote; // 代理对象被创建的时候被传入远程服务端IBinder Proxy(IBinder remote) { mRemote = remote; } public IBinder asIBinder() { return mRemote; } public String getInterfaceDescriptor() { return DESCRIPTOR; } // Proxy端口实现openMedia (会远程调用的服务端相应接口) @Override public int openMedia(String path) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(path); // 调用到服务端openMedia函数 mRemote.transact(Stub.TRANSACTION_openMedia, _data, _reply, 0); _reply.readException(); // 得到服务端返回码 _reply = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_openMedia = (IBinder.FIRST_CALL_TRANSACTION + 0); } // ======================================接口函数声明================================= /** * 打开媒体,但不播放 * @param path * @return 状态码 */ public int openMedia(java.lang.String path) throws android.os.RemoteException; // ======================================接口函数声明================================= }
三、服务端AudioPlayerService返回的IBinder对象继承抽象类Stub(需要实现 AudioPlayerAidl接口中的openMedia函数)
@Override public IBinder onBind(Intent intent) { return new LocalBinder(); } public LocalBinder extends AudioPlayerAidl.Stub { @Override public int openMedia(String path) throws RemoteException { return AudioPlayerService.this.openMedia(path); } }
四、在AudioPlayerService服务端真正的openMedia方法实现 (注意: 该服务是在单独的进程中运行,才会有这一系列的繁琐过程)
public int openMedia(String path) { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setDataSource(path); mMediaPlayer.prepare(); //..... }
五、在应用进程中(和服务端不在同一个进程)绑定服务时:
context.bindService(intent, mServiceConn, Service.BIND_AUTO_CREATE); private ServiceConnection mServiceConn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName arg0) { mAudioPlayerAidl = null; } @Override public void onServiceConnected(ComponentName cn, IBinder ib) { // 这个ib就是服务端的LocalBinder, 在这里用Proxy包装 mAudioPlayerAidl = AudioPlayerAidl.Stub.asInterface(ib); } };
服务端与客户端交互:(跨进程通信)
一、关键在于IBinder接口的transact函数
以及其实现类Binder的onTransact函数
1、服务端(提供服务的一方, 如本例中提供打开媒体的真正实现(AudioPlayerService所在进程))
其实就是 LocalBinder,它继承了 AudioPlayerAidl.Stub,而Stub不过是服务端的代理,继承了Binder,
因此也就实现了IBinder接口。
2、客户端
当客户端需要调用服务时, 使用服务端Stub.asInterface(IBinder ib)函数获取客户端代理Proxy,
Proxy中含有一个服务端的IBinder接口mRemote(其实就是LocalBinder), 这样调用IBinder的transact函数
就间接调用到了Stub(继承了Binder)中的onTransact函数
3、根据transact和onTransact的控制反转关系(code协议控制)
// Proxy中调用
// 传入的code值用来判断调用哪个函数
transact(int code, Parcel data, Parcel reply, int flags);
// Stub中调用
// 根据code值来具体调用服务端的函数
onTransact(int code, Parcel data, Parcel reply, int flags);
Binder的死亡代理:
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { if (mAudioPlayerAidl == null) return; mAudioPlayerAidl.asBinder().unlinkToDeath(mDeathRecipient, 0); mAudioPlayerAidl = null; // TODO: 在这里重新绑定远程Service } }; mAudioPlayerAidl = AudioPlayerAidl.Stub.asInterface(ib); ib.linkToDeath(mDeathRecipient, 0);