接着上一篇分析的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步:

  1. 根据code的值来判断client端具体想要调用哪个方法;
  2. 读取parcel对象(data)中传入的参数;
  3. 调用自己本地的方法(add)并将参数传入;
  4. 把结果写入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个事情:

  1. 创建两个parcel对象分别存放参数(data)和返回值(reply)
  2. 调用transact方法,传入data,reply,和你要调用的方法code。最后的flag传入0表示有返回值(1表示没有又返回值)
  3. 从reply中获得结果

完成以上工作就可以不通过aidl实现跨进程通讯了。但是还是要说一下,这里我们server端调用的只是一个简单的add方法不耗时的,而transact方法则是在onServiceConnected方法中被调用的其实是在主线程中执行的。如果add方法换成一个耗时方法,那么主线程(UI线程)是会卡死的,调用transact方法时当前线程会被挂起知道结果被返回(有兴趣可以去试试,只要在add方法里面加一个Thread.sleep就可以了)。所以最好的办法就是起一个线程来调用transact方法。

本文转自 一点点征服   博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/8418909.html,如需转载请自行联系原作者

Android进阶笔记:AIDL内部实现详解 (二)相关推荐

  1. 安卓 linux init.rc,[原创]Android init.rc文件解析过程详解(二)

    Android init.rc文件解析过程详解(二) 3.parse_new_section代码如下: void parse_new_section(struct parse_state *state ...

  2. Android init.rc文件解析过程详解(二)

    Android init.rc文件解析过程详解(二) 3.parse_new_section代码如下: void parse_new_section(struct parse_state *state ...

  3. Android学习笔记(6)——详解持久化技术

    第六章 数据存储权方案--详解持久化技术 6.1 持久化技术简介 概述:Android 系统中主要提供了3种方式用于简单地实现数据持久化功能,即文件存储.SharedPreference存储以及数据库 ...

  4. flutter 获取android 还是ios_Flutter完整开发实战详解(二十、 Android PlatformView 和键盘问题)...

    作为系列文章的第二十篇,本篇将结合官方的技术文档科普 Android 上 PlatformView 的实现逻辑,并且解释为什么在 Android 上 PlatformView 的键盘总是有问题. 为什 ...

  5. Android开发笔记之:Log图文详解(Log.v,Log.d,Log.i,Log.w,Log.e)

    本篇文章是对Android中的Log进行了详细的分析介绍,需要的朋友参考下 在Android群里,经常会有人问我,Android Log是怎么用的,今天我就把从网上以及SDK里东拼西凑过来,让大家先一 ...

  6. Android学习笔记5——Button属性详解

    前言 Button组件是在我们在开发中最常用到的组件.Button组件,俗称"按钮",在APP界面当中少不了按钮,那么按钮的属性和使用方法是怎么样的呢? Button常用属性 因为 ...

  7. Android Jetpack组件之数据库Room详解(二)

    本文涉及Library的版本如下: androidx.room:room-runtime:2.1.0-alpha03 androidx.room:room-compiler:2.1.0-alpha03 ...

  8. Android进阶笔记:Messenger源码详解

    Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析.相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个 ...

  9. 【Android Camera1】Camera1 Parameters参数详解(一)—— Size (preview/picture/thumbnail)

    1.简介 本篇文章将对Camera1和Size相关的参数,逐个进行详细解析.在Camera1源码分析文章里.已阐述过相关源码.并提供了读取和更新Parameters的2个方法如下: 读取Paramet ...

最新文章

  1. 【加】德鲁·卡宾森 - 质量效应2:升天(2013年6月7日)
  2. poi 拆分带图片的word_java poi设置生成的word的图片为上下型环绕以及其位置的实现...
  3. easyui 行编辑修改
  4. 在Linux上自动调整屏幕亮度保护眼睛
  5. 海南电网全力支持新能源发展
  6. Hadoop学习很好的书籍,理论和代码都有
  7. 1039: 二哥的困惑 Ⅱ
  8. @你最强资源包来了 MobTech 联合 LiveVideoStack 发起劳动光荣榜
  9. optimize table优化mysql例子
  10. 5页面放大再正常显示_一加5/5TFlyme8 9.9.24 功能一览
  11. 如何构建NTP时间服务器
  12. java byte 文件大小_java byte文件大小
  13. 如何从Oracle官网上下载JDK
  14. win10如何重装系统(联想笔记本)
  15. 网络编程之Socket零基础入门Demo
  16. Kaldi语音识别技术
  17. Origin2018(汉化版)在使用科学计数法的时候如何将坐标刻度的0.0改成0
  18. 时间序列的预处理——平稳性检验的R语言实现(二)
  19. 设置单选框只能选择一个
  20. PERCENT(SQL)

热门文章

  1. 常用SQL语句和HQL语句写法
  2. 约瑟夫问题的循环链表实现
  3. c# 利用反射获得某个类或者对象的所有属性
  4. 中山计算机编程,中山plc编程设计
  5. 【数字信号处理】相关函数应用 ( 相关函数应用场景 | 噪声中检测信号原理 )
  6. 【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | dvmDexFileOpenPartial | dexFileParse | 脱壳点 | 获取 dex 文件在内存中的首地址 )
  7. 【Android 安装包优化】Android 中使用 7zr 可执行程序 压缩文件
  8. 【鸿蒙 HarmonyOS】UI 组件 ( 文本输入框 TextField 组件 )
  9. 使用html5 Geolocation显示你的地理位置
  10. [kuangbin带你飞]专题四 最短路练习 B( POJ 2253) Frogger(spfa)