了解 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的认识比较模糊,没有进行系统整理. 今天查阅了相关资料,觉得写得很不错,所以我试图在博文中对资料进行整理一下,再 ...
随机推荐
- 移动UI设计中需要避免的四种常见用户体验误区
2012年移动应用的下载量超过300 亿,可是智能手机用户平均每周会使用的应用数却大概只有15个.更糟的是,Localytics 的研究表明,大概有22%的应用是见光死,用过一次之后就被束之高阁.既然 ...
- Spring boot配置fastjson
pom 文件引用 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson< ...
- 如何将.sof转换成.jic
因为不同版本的QUARTUS II可能界面稍有差异,因此就不做截图演示了,只说操作步骤: 1.通过综合生成包含FPGA配置数据的.sof文件 2.选择转换编程文件,菜单File->convert ...
- quartusii开发过程中路径不能出现空格或中文
quartusii开发过程中路径不能出现空格或中文,否则软件出现.stf文件错误提示,开发环境搭建的时候也不能出现空格和中文,否则也会报错.
- python开发者通过国内镜像安装pip包
对于Python开发用户来讲,PIP安装软件包是家常便饭.但国外的源下载速度实在太慢,浪费时间.而且经常出现下载后安装出错问题.所以把PIP安装源替换成国内镜像,可以大幅提升下载速度,还可以提高安装成 ...
- django Multi-table inheritance ---- 用于实现基表-子表
SQL中的父子表.在django中可以直接通过模式的继承来完成! 一.django中的model定义如下: 1.django定义 from django.db import models # Crea ...
- CentOS中安装JDK与Intellij idea
卸载CentOS中自带openjdk CentOS自带openjdk,可以先用java –version检测是否存在jdk版本.如果存在,最好在安装oracle的jdk之前最好卸载,可以使用如下指令 ...
- Oracle 10g如何对用户姓名,按首字母排序、查询
首先介绍Oracle 9i新增加的一个系统自带的排序函数 1.按首字母排序 在oracle9i中新增了按照拼音.部首.笔画排序功能.设置NLS_SORT值 SCHINESE_RADICA ...
- python登陆Tom邮箱的代码一例
本文出处参考:http://www.cnblogs.com/LinuxHunter/archive/2010/11/30/1891635.html 在很多的python 教程中都会讲到登录邮箱或发送邮 ...
- TIM—高级定时器
本章参考资料:< STM32F4xx 参考手册>.< STM32F4xx 规格书>.库帮助文档< stm32f4xx_dsp_stdperiph_lib_um.chm&g ...