AIDL的Proxy-Stub理解:(以实际媒体播放器服务单独运行在一个进程中为例)
来源:互联网 发布:淘宝官方活动报名 编辑:程序博客网 时间:2024/06/05 07:33
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);}@Overridepublic IBinder asBinder() {return this;}// 该函数由父类transact调用 (根据code码确定调用哪个函数),接收来自客户端的请求@Overridepublic 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();// 注意,从这里调用到了在服务端实现的openMediaint _result = this.openMedia(path);reply.writeNoException();reply.writeInt(result);return true;}}// 父类Binder处理return super.onTransact(code, data, reply, flags);}// Stub的内部类Proxyprivate static class Proxy implements AudioPlayerAidl {// 服务端IBinder接口private IBinder mRemote;// 代理对象被创建的时候被传入远程服务端IBinderProxy(IBinder remote) {mRemote = remote;}public IBinder asIBinder() {return mRemote;}public String getInterfaceDescriptor() {return DESCRIPTOR;}// Proxy端口实现openMedia (会远程调用的服务端相应接口)@Overridepublic 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函数)
@Overridepublic IBinder onBind(Intent intent) {return new LocalBinder();}public LocalBinder extends AudioPlayerAidl.Stub {@Overridepublic 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() {@Overridepublic void onServiceDisconnected(ComponentName arg0) {mAudioPlayerAidl = null;}@Overridepublic 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);
0 0
- AIDL的Proxy-Stub理解:(以实际媒体播放器服务单独运行在一个进程中为例)
- Aidl中Stub和Stub.Proxy的理解
- 理解Aidl中Stub和Stub.Proxy
- Android AIDL 跨进程服务 Proxy/Stub
- 从android aidl理解Proxy/stub模式
- 从android aidl理解Proxy/stub模式
- 从android aidl理解Proxy/stub模式
- 从Proxy-Stub到aidl
- Android AIDL proxy/stub 分析
- js代码跟html如上,单独放在一个页面运行测试就可以,可当放到实际项目中只滚动2次就停了。原因
- 运行在单独进程中的ContentProvider
- 运行在单独进程中的ContentProvider
- 运行在单独进程中的ContentProvide…
- 运行在单独进程中的ContentProvider
- 使代码运行在一个单独的线程中的方法
- 在一个后台服务中运行
- 以实际产品为例, 进行软件工程训练的作业
- 以实际产品为例, 进行软件工程训练的作业
- rsyslogd: error during parsing file /etc/rsyslog.conf, on or before line 55: warnings occured in fil
- zookeeper运维
- 1019. General Palindromic Number (20)-PAT甲级真题
- Object-c 不错的视频教程
- Guest OS, Qemu, KVM工作流程
- AIDL的Proxy-Stub理解:(以实际媒体播放器服务单独运行在一个进程中为例)
- 短信验证具体步骤
- UITableViewCell 的Image设置了UIViewContentModeScaleAspectFill后图片超出去了
- LeetCode Algorithms3: Longest substring without repeating characters(in swift)
- centos 7 mysqlhotcopy 安装,使用 笔记
- Netlink实现热拔插监控
- MySQL 数据备份与还原
- zabbix监控报错zabbix server is not running: the information displayed may not be current
- Kali linux