了解 IMyInterface.Stub
Service中的IBinder
还记得我们在MyService中利用new IMyInterface.Stub()向上转型成了IBinder然后在onBind方法中返回的。那我们就看看IMyInterface.Stub吧:
public static abstract class Stub extends android.os.Binder implements aidl.IMyInterface {
..........
}
可以看到,Stub是IMyInterface中的一个静态抽象类,继承了Binder,并且实现了IMyInterface接口。这也就解释了我们定义IMyInterface.Stub的时候为什么需要实现IMyInterface中的方法了,也说明了为什么我们可以把IMyInterface.Stub向上转型成IBinder了。
Activity中的IMyInterface
在Activity中,通过ServiceConnection连接MyService并成功回调onServiceConnected中我们把传回来的IBinder通过IMyInterface.Stub.asInterface(service)转换成为IMyInterface,那就来看看这里是如何转换的吧:
public static abstract class Stub extends android.os.Binder implements aidl.IMyInterface {
..........
public static aidl.IMyInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//检查Binder是不是在当前进程
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof aidl.IMyInterface))) {
return ((aidl.IMyInterface) iin);
}
return new aidl.IMyInterface.Stub.Proxy(obj);
}
}
首先,我们因该明白的是,传回来的IBinder就是我们在Service的onBind( )方法所return的IBinder,然后我们调用Stub中的静态方法asInterface并把返回来的IBinder当参数传进去。
在asInterface方法中,首先判断了传进来的IBinder是不是null,如果为null就返回一个null;接着就判断传进来的IBinder是不是就在当前进程里面,如果是的话就直接返回IMyInterface,不是的话就返回IMyInterface.Stub.Proxy(obj)。这里我觉得需要明白的是:直接返回的IMyInterface是实现了定义的接口方法getInfor的。因为在IMyInterface.Stub中所实现的。当然如果是在同一进程中,那么我们调用IMyInterface的方法时就是在本地调用方法,直接调用就可以了。
如果没在同一进程,就会返回IMyInterface.Stub.Proxy(obj):
private static class Proxy implements aidl.IMyInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public java.lang.String getInfor(java.lang.String s) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(s);
//传送数据到远程的
mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);
_reply.readException();
//接受从远端传回的数据
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getInfor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
在Proxy中,我们首先把Service连接成功返回的IBinder它的内部变量mRemote,这里在提一下,这里得IBinder还是是MyService中onBind所返回的。然后,当我们调用IMyInterface的方法的时候,其实就是调用的Proxy的方法了,这也是为什么这个类叫做Porxy的原因了。
当调用IMyInterface.getInfor(String s) ,我们就看Proxy中的getInfor,先获取了两个Parcel对象 _data、_data,从变量名就可以看出,一个是传送数据的,另一个则是接受返回数据的。接着,向_data中写入了DESCRIPTOR(也就是这个类的全名),再写入了方法参数。然后就到了最重要的一步了,
mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);
这里我们调用了IBinder的transact方法,来把数据传给远端的服务器。然后在我们远程的MyService中,里面的Stub中就会回调onTransact()(因为你把数据传个远程的服务,远端的服务收到数据也就回调了)
注意:这里是在远程的服务里调用的。
@Overridepublic
boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getInfor: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
//取出参数
_arg0 = data.readString();
// 远程服务调用自己本地实现的方法获取返回值
java.lang.String _result = this.getInfor(_arg0);
reply.writeNoException();
//写入返回值
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
onTransact方法是在Stub的内部实现的。
先看一下它的四个参数:
code:每个方法都有一个int类型的数字用来区分(后面中的swicth),在我们例子中也就是我们Proxy中的Stub.TRANSACTION_getInfor。
data:传过来的数据,其中包含我们的参数,以及类的描述。
reply:传回的数据,我们要写入是否发生了Exception,以及返回值
flags:该方法是否有返回值 ,0表示有返回值。
调用onTransact就表示有数据传来,首先就会通过swicth判断是哪个方法,然后取出方法参数,调用本地实现的方法获取返回值,写入返回值到reply。最后,返回true,才会把数据发送出去,发挥false就不会把结果返回给Activity了。这里也就是说,只有返回true,我们Proxy中才能接受从远端传回的数据。
//传送数据到远程的
mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);
_reply.readException();
//接受从远端传回的数据
_result = _reply.readString();
注意:Service也是把数据发送出来,让客户端接受的。
Service发出了数据,客户端接收到了,就会一层一层返回去。所以,当我们简单的调用IMyInterface的getInfor时候,先是Proxy的transact发送出数据,然后服务端的onTransact接受并处理传来的数据,再把处理得到的数据写入返回值并发送给客户端,客户端读取值后就成为调用方法的返回值返回了。
了解 IMyInterface.Stub的更多相关文章
- Python爬取CSDN博客文章
0 url :http://blog.csdn.net/youyou1543724847/article/details/52818339Redis一点基础的东西目录 1.基础底层数据结构 2.win ...
- Android 中AIDL的使用与理解
AIDL的使用: 最常见的aidl的使用就是Service的跨进程通信了,那么我们就写一个Activity和Service的跨进程通信吧. 首先,我们就在AS里面新建一个aidl文件(ps:现在AS建 ...
- What's the difference between a stub and mock?
I believe the biggest distinction is that a stub you have already written with predetermined behavio ...
- 初识 PHPunit stub 模拟返回数据
这是这段时间以来结合 PHPunit 文档和大牛们的讲解,想记录下自己学习到的知识,未来参考补充,完善学到的东西 我们一般使用单测对公司业务里的代码进行测试,他会帮忙找到你的一个个小小的思考不够全面的 ...
- 深入浅出 - Android系统移植与平台开发(八)- HAL Stub框架分析
作者:唐老师,华清远见嵌入式学院讲师. 1. HAL Stub框架分析 HAL stub的框架比较简单,三个结构体.两个常量.一个函数,简称321架构,它的定义在:@hardware/libhardw ...
- 存根类STUB
当我们创建一个指定各种方法集合的接口时,我们可以考虑使用"存根”STUB,“存根”就是用空方法体实现该接口中所有方法的类,这样我们就可以通过继承该“存根”创建一个实现该接口的类,这样一来,该 ...
- AIDL与stub
Stub翻译成中文是存根的意思,注意Stub对象是在被调用端进程,也就是服务端进程,至此,服务端aidl服务端得编码完成了. stub是为了方便client,service交互而生成出来的代码.A ...
- 使用Mockito进行单元测试【2】—— stub 和 高级特性[转]
一篇中介绍了Mockito的基本信息,现在接着介绍Mockito强大的stub功能 2. Mockito使用实例 5. 对连续的调用进行不同的返回 (iterator-style stubbing) ...
- Stub和Mock的理解
我对Stub和Mock的理解 介绍 使用测试驱动开发大半年了,我还是对Stub和Mock的认识比较模糊,没有进行系统整理. 今天查阅了相关资料,觉得写得很不错,所以我试图在博文中对资料进行整理一下,再 ...
随机推荐
- FFmpeg采集音视频数据命令
文章转自:https://www.jianshu.com/p/4709ccbda3f9 1.ffmpeg 把文件当做直播推送至服务器 (RTMP + FLV) ffmpeg - re -i demo. ...
- operator new 和 operator delete 实现一个简单内存泄漏跟踪器
先来说下实现思路:可以实现一个Trace类,调用 operator new 的时候就将指向分配内存的指针.当前文件.当前行等信息添加进Trace 成员map容器内,在调用operator delete ...
- 浅谈LZSS与游戏图片破解
业余游戏制作者最头疼的就是没有美工的支持了.很多业余游戏制作所使用的图片都是来自于网上的很有限的一些图片资源,然而这些图片并不能完整配套,所以业余游戏的画面往往显得单调或者搭配不协调(使用多个不属 ...
- MS SQL表字段自增相关的脚本
--查询表是否有自增字段 SELECT OBJECTPROPERTY(OBJECT_ID('[表名]'), 'TableHasIdentity') --查询表的自增字段 SELECT COLUMN_N ...
- centos系统字符编码问题
1.cat /etc/locale.conf LANG="en_US.UTF-8" 2./etc/profile.d/lang.sh这个文件要有且可以正常执行(检查/sbin/co ...
- Python黑魔法,一行实现并行化
Python 在程序并行化方面多少有些声名狼藉.撇开技术上的问题,例如线程的实现和 GIL,我觉得错误的教学指导才是主要问题.常见的经典 Python 多线程.多进程教程多显得偏“重”.而且往往隔靴搔 ...
- -[__NSArrayI removeAllObjects]: unrecognized selector sent to instance 0x7fa8dc830110
问题 今天做项目,遇到了这个问题 -[__NSArrayI removeAllObjects]: unrecognized selector sent to instance 0x7fa8dc8301 ...
- Java的==与equals之辨,简单解释,很清楚
"=="和equals方法究竟有什么区别? (单独把一个东西说清楚,然后再说清楚另一个,这样,它们的区别自然就出来了,混在一起说,则很难说清楚) ==操作符专门用来比较两个变量的值 ...
- FileInputStream与FileOutputStream类
FileInputStream和FileOutputStream类分别用来创建磁盘文件的输入流和输出流对象,通过它们的构造函数来指定文件路径和文件名. 创建FileInputStream实例对象时,指 ...
- Setup Factory 读取安装包的配置文件
result = INIFile.GetValue(SessionVar.Expand("%SourceFolder%\\set.ini"), "set", & ...