Android进阶笔记:AIDL内部实现详解 (二)
接着上一篇分析的aidl的流程解析。知道了aidl主要就是利用Ibinder来实现跨进程通信的。既然是通过对Binder各种方法的封装,那也可以不使用aidl自己通过Binder来实现跨进程通讯。那么这篇博客就主要就写一下通过上篇(Android进阶笔记:AIDL详解(一))总结的知识来自己实现跨进程通讯从而更加透彻的了解aidl的核心逻辑。
首先上一篇博客(Android进阶笔记:AIDL详解(一))中总结出一个结论————“onTransact方法是提供给server端用的,transact方法(内部类proxy封装了transact方法)和asInterface方法是给client端用的。”因此很清楚,只要我们在Server端实现跨进程需要调用的方法(类似aidl的接口实现)和onTransact方法,而服务端只要通过获得的IBinder对象来调用transact方法就可以代替aidl来实现跨进程通讯了。既然思路已经整理清楚了,那就一步一步来实现它。
Server端
首先Server端是要通过Service的onBind方法来给Client端一个Binder对象,那就先从这个Binder对象入手。那就先来创建了一个MyBinder类,代码如下:
MyBinder.java
public class MyBinder extends Binder {
//标记方法的
private static final int METHOD_ADD_CODE = 1001;
//标识binder对象的
private static final String DESCRIPTION = "not use aidl";
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
if (code == METHOD_ADD_CODE) {
//验证一下binder
data.enforceInterface(DESCRIPTION);
//从parcel对象中读取参数
int arg0 = data.readInt();
int arg1 = data.readInt();
//写入结果
reply.writeInt(add(arg0, arg1));
return true;
}
return super.onTransact(code, data, reply, flags);
}
private int add(int arg0, int arg1) {
return arg0 + arg1;
}
}
代码非常简单,只是重新写了一下onTransact方法。其实一共只有4步:
- 根据code的值来判断client端具体想要调用哪个方法;
- 读取parcel对象(data)中传入的参数;
- 调用自己本地的方法(add)并将参数传入;
- 把结果写入parcel对象(reply)中;
接着只要把这个自己定义的MyBinder类的实例通过Service.onBInder方法返回给Client端就可以了。
MyService.java
public class MyService extends Service {
private MyBinder myBinder;
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
//创建实例
myBinder = new MyBinder();
}
@Override
public IBinder onBind(Intent intent) {
//返回自定义的binder对象
return myBinder;
}
}
Client端
client端的代码无非就是把之前写在aidl中的proxy内部类的方法拿出来了。具体看代码:
WithoutAidlActivity.java
public class WithoutAidlActivity extends AppCompatActivity {
private ServiceConnection serviceConnection;
private IBinder binder;
//以下两个参数要和server端保持一致
//标记方法的(告知server端调用哪个方法)
private static final int METHOD_ADD_CODE = 1001;
//标识binder对象的
private static final String DESCRIPTION = "not use aidl";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_without_aidl);
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("onServiceConnected", "onServiceConnected: connected success!");
binder = service;
//这里就代替aidl中的proxy来直接调用transact方法
//先准备参数
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(DESCRIPTION);
data.writeInt(123);
data.writeInt(456);
try {
//调用transact方法
binder.transact(METHOD_ADD_CODE, data, reply, 0);
//获得结果
int result = reply.readInt();
Log.d("onServiceConnected", "result = " + result);
} catch (RemoteException e) {
e.printStackTrace();
} finally {
data.recycle();
reply.recycle();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
binder = null;
}
};
bindService(new Intent("com.coder_f.aidlserver.MyService"), serviceConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
首先连接成功后在serviceConnection.onServiceConnected方法中获得了IBinder实例,然后总共做了3个事情:
- 创建两个parcel对象分别存放参数(data)和返回值(reply)
- 调用transact方法,传入data,reply,和你要调用的方法code。最后的flag传入0表示有返回值(1表示没有又返回值)
- 从reply中获得结果
完成以上工作就可以不通过aidl实现跨进程通讯了。但是还是要说一下,这里我们server端调用的只是一个简单的add方法不耗时的,而transact方法则是在onServiceConnected方法中被调用的其实是在主线程中执行的。如果add方法换成一个耗时方法,那么主线程(UI线程)是会卡死的,调用transact方法时当前线程会被挂起知道结果被返回(有兴趣可以去试试,只要在add方法里面加一个Thread.sleep就可以了)。所以最好的办法就是起一个线程来调用transact方法。
Android进阶笔记:AIDL内部实现详解 (二)的更多相关文章
- Android进阶之AIDL的使用详解
原文首发于微信公众号:jzman-blog,欢迎关注交流! AIDL(Android 接口定义语言),可以使用它定义客户端与服务端进程间通信(IPC)的编程接口,在 Android 中,进程之间无法共 ...
- Android进阶笔记:AIDL内部实现详解 (一)
AIDL内部实现详解 (一) AIDL的作用是实现跨进程通讯使用方法也非常的简单,他的设计模式是典型的C/S架构.使用AIDL只要在Client端和Server端的项目根目录下面创建一个aidl的文件 ...
- Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)
[Android布局学习系列] 1.Android 布局学习之——Layout(布局)详解一 2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数) 3.And ...
- 我的Android进阶之旅------>HTTP Header 详解
HTTP(HyperTextTransferProtocol)即超文本传输协议,目前网页传输的的通用协议.HTTP协议采用了请求/响应模型,浏览器或其他客户端发出请求,服务器给与响应.就整个网络资源传 ...
- 【Android进阶】Application对象的详解
1:Application是什么? Application和Activity,Service一样,是android框架的一个系统组件,当android程序启动时系统会创建一个 application对 ...
- Android进阶笔记:Messenger源码详解
Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析.相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个 ...
- Android笔记-2-TextView的属性详解
[Android 基础]TextView的属性详解 android:autoLink :设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接.可选值(none/web / ...
- PopUpWindow使用详解(二)——进阶及答疑
相关文章:1.<PopUpWindow使用详解(一)——基本使用>2.<PopUpWindow使用详解(二)——进阶及答疑> 上篇为大家基本讲述了有关PopupWindow ...
- Android 多线程之IntentService 完全详解
关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...
随机推荐
- leetcode 之Valid Palindrome(26)
现在开始进入字符串系列. 判断回文串的.首尾各定义一个指针,然后相比较.难点在于如何提出非字母数字的字符. bool isValidPalind(string s) { //转为小写,注意这个函数的用 ...
- CF914F Substrings in a String
Description 给你一个字符串ss,共有qq次操作,每个都是下面两种形式的一种. 11 ii cc 这个操作表示将字符串ss的第ii项变为字符cc 22 ll rr yy 这个操作表示输出字符 ...
- yum 安装 jdk
https://www.cnblogs.com/kevingrace/p/5870814.html yum -y list java* 以yum库中java-1.7.0为例注:“*”表示将java-1 ...
- 深度学习方法:受限玻尔兹曼机RBM(二)网络模型
欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入 上解上一篇RBM(一)基本概念, ...
- Eolinker——前置用例的使用
如下补充均是Eolinker的文档中未说明的部分 1.在Eolinker的API自动化测试中,点击“前置用例”,“添加前置用例” 2.给添加的接口命名完之后,点击名称进入到编辑页面,代码输入框的内容为 ...
- CodeForces 738C Road to Cinema
二分答案. 油量越多,显然通过的时间越少.可以二分找到最小的油量,可以在$t$时间内到达电影院. 一个油箱容量为$v$的车通过长度为$L$的路程需要的最小时间为$max(L,3*L-v)$.计算过程如 ...
- 决策树:ID3与C4.5算法
1.基本概念 1)定义: 决策树是一个预测模型:他代表的是对象属性与对象值之间的一种映射关系,树中每个节点代表的某个可能的属性值. 2)表示方法: 通过把实例从根结点排列到某个叶子结点来分类实例,叶子 ...
- Java使用Redis初探
Redis的相关概念不做介绍了,大家也可以先了解下Memcached,然后比较下二者的区别,就会有个整体的印象. 服务器端通常选择Linux , Redis对于linux是官方支持的,使用资料很多,需 ...
- CAS无锁操作
https://coolshell.cn/articles/8239.html 主要讲的是<Implementing Lock-Free Queues>的论点,具体直接看论文最好.这里总结 ...
- CSS3选择器、低版本解决方案及各浏览器私有前缀
一.基本选择器 通配选择器:* 元素选择器:div.p… ID选择器:#id 类选择器:.className 群组选择器:选择器1,选择器2 主流浏览器全部支持 二.层次选择器 后代选择器: div ...