Android IPC系列(一):AIDL使用详解

概述

AIDL可以实现进程间的通信,由于每个进程都是运行在独立的空间,不同的进程想要交互需要借助一些特殊的方式,AIDL就是其中的一种,AIDL是一种模板,因为实际交互过程中,并不是AIDL起的作用,具体会在之后源码分析解释,AIDL的作用是为了避免重复编写代码而出现的一个模板

语法

AIDL的语法十分简单,与Java语言基本保持一致,需要记住的规则有以下几点:

  • AIDL文件以 .aidl 为后缀名 AIDL支持的数据类型分为如下几种:

    • 八种基本数据类型:byte、char、int、long、float、double、boolean String,CharSequence,其中不支持short类型
    • 实现了Parcelable接口的数据类型
    • List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
    • Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
  • 定向Tag。定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分为 in、out、inout 三种。其中

    • in 表示数据只能由客户端流向服务端
    • out 表示数据只能由服务端流向客户端
    • inout 则表示数据可在服务端与客户端之间双向流通
    • 此外,如果AIDL方法接口的参数值类型是:基本数据类型、String、CharSequence或者其他AIDL文件定义的方法接口,那么这些参数值的定向 Tag 默认是且只能是 in,所以除了这些类型外,其他参数值都需要明确标注使用哪种定向Tag。定向Tag具体的使用差别后边会有介绍
  • 明确导包。在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下

服务端

  • 先建立一个项目
  • 由于要传输自定义User对象,所以定义一个User的aidl文件,直接生成
    创建完成后,系统就会默认创建一个 aidl 文件夹,文件夹下的目录结构即是工程的包名,Book.aidi 文件就在其中 然后更改User.aidl文件内容
package com.baidu.bpit.aibaidu.aidl;parcelable User;
复制代码
  • 然后生成一个User的类,实现Parcelable
public class User implements Parcelable {public String name;public User(String name){this.name=name;}protected User(Parcel in) {name = in.readString();}public static final Creator<User> CREATOR = new Creator<User>() {@Overridepublic User createFromParcel(Parcel in) {return new User(in);}@Overridepublic User[] newArray(int size) {return new User[size];}};@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(name);}
}
复制代码
  • 然后在定义一个BookName的aidl文件,向客户端暴露可调用的接口,需要手动导入User,import com.baidu.bpit.aibaidu.aidl.User;
package com.baidu.bpit.aibaidu.aidl;
import com.baidu.bpit.aibaidu.aidl.User;
interface BookName {String getName();List<User> getList();}
复制代码
  • 这时候重新build一下工程
  • 现在需要来创建一个 Service 供客户端远程绑定了,返回你的自定义的Binder

public class ServiceService extends Service {public ServiceService() {}@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}class MyBinder extends BookName.Stub {@Overridepublic String getName() throws RemoteException {return "西游记";}@Overridepublic List<User> getList() throws RemoteException {User user = new User("111");User user1 = new User("222");List<User> users = new ArrayList<>();users.add(user1);users.add(user);return users;}}
}
复制代码
  • AndroidManifest.xml文件定义
 <serviceandroid:name=".ServiceService"android:enabled="true"android:exported="true"><intent-filter><action android:name="com.aaa.aaa" /></intent-filter></service>
复制代码

客户端

  • 首先把服务端的aidl文件夹,整体复制到客户端
  • 之后,需要创建和服务端User类所在的相同包名来存放 User类
  • 在MainActivity绑定服务端的service,点击按钮获取书名

public class MainActivity extends AppCompatActivity {private BookName bookName;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bindServer();initView();}private void initView() {findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {Log.d("mmmgetName", bookName.getName());List<User> list = bookName.getList();for (User user : list) {Log.d("mmmgetList", user.name);}} catch (RemoteException e) {e.printStackTrace();}}});}private void bindServer() {Intent mIntent = new Intent();//你定义的service的actionmIntent.setAction("com.aaa.aaa");//这里你需要设置你应用的包名mIntent.setPackage("com.baidu.bpit.aibaidu.aidl");bindService(mIntent, new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {bookName = BookName.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {}}, BIND_AUTO_CREATE);}
}复制代码
  • 点击按钮打印
01-18 22:11:17.642 4542-4542/com.baidu.bpit.aibaidu.client D/mmmgetName: 西游记
01-18 22:11:17.643 4542-4542/com.baidu.bpit.aibaidu.client D/mmmgetList: 222111
复制代码

正确获取数据

定向TAG

有三种定向TAG

  • inout:服务端修改数据,会同步到客户端,因此可以说数据是双向流动的
  • in:数据只从客户端流向服务端,服务端修改数据不会影响客户端
  • out:数据只能由服务端传向客户端,及时客户端传入一个对象,这个对象也是空的,即没有数据,服务端获取该对象后,对该对象任何操作都会同步到客户端这里

修改aidl

interface BookName {String getName();List<User> getList();void addInout(inout User user);void addIn(in User user);void addout(out User user);}
复制代码

这次增加了三个方法addInout,addIn,addout,之后分别测试这三个方法

修改User类 User类需要添加俩个方法,一个无参构造,一个readFromParcel

public class User implements Parcelable {public String name;public User(){}public User(String name){this.name=name;}protected User(Parcel in) {name = in.readString();}public static final Creator<User> CREATOR = new Creator<User>() {@Overridepublic User createFromParcel(Parcel in) {return new User(in);}@Overridepublic User[] newArray(int size) {return new User[size];}};@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(name);}public void readFromParcel(Parcel dest) {name = dest.readString();}
}
复制代码

先测试一下inout

服务端


public class ServiceService extends Service {public ServiceService() {}@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}class MyBinder extends BookName.Stub {@Overridepublic String getName() throws RemoteException {return "西游记";}@Overridepublic List<User> getList() throws RemoteException {User user = new User("111");User user1 = new User("222");List<User> users = new ArrayList<>();users.add(user1);users.add(user);return users;}@Overridepublic void addInout(User user) throws RemoteException {Log.d("mmmserver","服务端获取到:"+user.name);user.name="服务端更改";Log.d("mmmserver","服务端修改书名:"+user.name);}@Overridepublic void addIn(User user) throws RemoteException {}@Overridepublic void addout(User user) throws RemoteException {}}
}
复制代码

主要看inout方法,服务端接受到客户端传来的信息后,修改信息内容

客户端

  private void initView() {findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {User user = new User("客户端传入");Log.d("mmmclient", "客户端向服务端传入一本书,书名:" + user.name);bookName.addInout(user);Log.d("mmmclient", "服务端修改书名后,书名:" + user.name);} catch (RemoteException e) {e.printStackTrace();}}});}
复制代码

点击按钮后,向服务端传入数据,服务端收到数据,会对数据更改,客户端再次查看此数据,看是否同步

01-18 23:15:18.529 5606-5606/com.baidu.bpit.aibaidu.client D/mmmclient: 客户端向服务端传入一本书,书名:客户端传入
01-18 23:15:18.529 5527-5554/com.baidu.bpit.aibaidu.aidl D/mmmserver: 服务端获取到:客户端传入
01-18 23:15:18.530 5527-5554/com.baidu.bpit.aibaidu.aidl D/mmmserver: 服务端修改书名:服务端更改
01-18 23:15:18.530 5606-5606/com.baidu.bpit.aibaidu.client D/mmmclient: 服务端修改书名后,书名:服务端更改
复制代码

看到服务端修改可以及时同步到客户端,这就是inout 数据双向流动

测试in

服务端

  @Overridepublic void addIn(User user) throws RemoteException {Log.d("mmmserverIn", "服务端获取到:" + user.name);user.name = "服务端更改";Log.d("mmmserverIn", "服务端修改书名:" + user.name);}
复制代码

客户端

    private void initView() {findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {User user = new User("客户端传入");Log.d("mmmclient", "客户端向服务端传入一本书,书名:" + user.name);bookName.addIn(user);Log.d("mmmclient", "服务端修改书名后,书名:" + user.name);} catch (RemoteException e) {e.printStackTrace();}}});}
复制代码

当点击按钮,会发送数据到服务端,服务端会更改数据内容,客户端再次查看数据,看是否被改变

01-18 23:26:23.079 5815-5815/com.baidu.bpit.aibaidu.client D/mmmclient: 客户端向服务端传入一本书,书名:客户端传入
01-18 23:26:23.080 5736-5763/com.baidu.bpit.aibaidu.aidl D/mmmserverIn: 服务端获取到:客户端传入
01-18 23:26:23.081 5736-5763/com.baidu.bpit.aibaidu.aidl D/mmmserverIn: 服务端修改书名:服务端更改
01-18 23:26:23.081 5815-5815/com.baidu.bpit.aibaidu.client D/mmmclient: 服务端修改书名后,书名:客户端传入
复制代码

看以看出服务端修改数据,并不会影响客户端

测试OUT

服务端

  @Overridepublic void addout(User user) throws RemoteException {Log.d("mmmserverout", "服务端获取到:" + user.name);user.name = "服务端更改";Log.d("mmmserverout", "服务端修改书名:" + user.name);}
复制代码

客户端

private void initView() {findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {User user = new User("客户端传入");Log.d("mmmclient", "客户端向服务端传入一本书,书名:" + user.name);bookName.addout(user);Log.d("mmmclient", "服务端修改书名后,书名:" + user.name);} catch (RemoteException e) {e.printStackTrace();}}});}
复制代码

客户端向服务端传入数据,服务端收到后,更改数据,客户端再次查看数据

01-18 23:36:21.997 6100-6100/com.baidu.bpit.aibaidu.client D/mmmclient: 客户端向服务端传入一本书,书名:客户端传入
01-18 23:36:21.998 6023-6037/com.baidu.bpit.aibaidu.aidl D/mmmserverout: 服务端获取到:null服务端修改书名:服务端更改
01-18 23:36:21.998 6100-6100/com.baidu.bpit.aibaidu.client D/mmmclient: 服务端修改书名后,书名:服务端更改
复制代码

可以看到服务端收到的是空对象,服务端更改影响客户端

GitHub: 参考:www.jianshu.com/p/29999c1a9…

转载于:https://juejin.im/post/5d4d12e7518825237b5bdb4d

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361538.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用单例EJB,Ehcache和MBean构建和清除参考数据缓存

在本文中&#xff0c;我将介绍如何使用单例EJB和Ehcache在Java EE中构建简单的参考数据缓存。 高速缓存将在给定的时间段后重置自身&#xff0c;并且可以通过调用REST端点或MBean方法“手动”清除。 这篇文章实际上是在以前的文章的基础上建立的 。 唯一的区别是&#xff0c;我…

深入浅出React Native 1: 环境配置

该教程主要介绍如何用react native来开发iOS&#xff0c;所以首先&#xff0c;你需要有一台mac&#xff0c;当然黑苹果也是可以的~ 创建一个react native的项目只需要安装以下五个组件~~&#xff08;但....坑爹的是&#xff0c;不FQ的话安装慢成狗呀&#xff09; 1. 安装 xco…

C#排序算法大全

C#排序算法大全 土人 2004-7-21 一、冒泡排序(Bubble) using System; namespace BubbleSorter { public class BubbleSorter { public void Sort(int[] list) { int i,j,temp; bool donefalse; j1; while((j<list.Length)&&(!done)) { donetrue; for…

Spring实战(前言:Spring容器)

Spring容器&#xff0c;顾名思义是用来容纳东西的&#xff0c;装的就是Bean。Spring容器负责创建、配置、管理Bean。spring容器有两个核心接口&#xff1a;BeanFactory和ApplicationContext接口&#xff0c;后者是前者的子接口。在基于spring的Java EE程序中&#xff0c;所有的…

具有WildFly,Arquillian,Jenkins和OpenShift的Java EE 7部署管道

技术提示&#xff03;54展示了如何Arquillianate&#xff08;Arquillianize&#xff1f;&#xff09;一个现有的Java EE项目并在WildFly在已知主机和端口上运行的远程模式下运行这些测试。 技术提示&#xff03;55展示了当WildFly在OpenShift中运行时如何运行这些测试。 这两个…

《那些年啊,那些事——一个程序员的奋斗史》——88

谁也不知道武总脑袋里面会想些什么。这天早上段伏枥还在发愁如何改进这4.3机器的电源管理的时候&#xff0c;武总突然让自己到会议室开会。 段伏枥还没坐下来的时候&#xff0c;武总推过来一台机器&#xff0c;说:“你看看&#xff0c;这机器怎么样。” 段伏枥定睛一看&#xf…

css浮动(float)及清除浮动的几种实用方法

CSS浮动是现在网页布局中使用最频繁的效果之一,而浮动可以帮我们解决很多问题,那么就让我们一起来看一看如何使用浮动. 一.css浮动(float) (1)html文档流 自窗体自上而下分成一行一行&#xff0c;并在每行中按从左到右的顺序排放元素。 (2)网页中大部分对象默认是占用文档流…

一台电脑同时添加git和bitbucket两个网站的ssh key

添加第一个ssh key 就不多说了&#xff0c;不懂的可以自己查资料 ssh-keygen -t rsa -C email_1email.com 然后一路enter就好了 假设已经添加好了git的ssh key 。现在要添加bitbucket的ssh key 首先 ssh-keygen -t rsa -C email_2email.com //同一个邮箱也可以 然后指定公钥的…

属性提取器:获取ListView即时更新其元素的最佳方法

这篇文章是关于如何处理JavaFX ListViews和TableViews的&#xff0c;以及这些控件如何得知所包含元素的更改内容。 我想知道为什么在相关书籍中没有找到关于以下模式的任何信息&#xff0c;因为这是一个非常关键的机制。 那里的许多帖子建议通过调用以下命令来强制触发ChangeEv…

基于python语言下的UI自动化测试框架搭建(四)

testsuits:案例执行 创建baidu_search1.py文件&#xff0c;这里会展示两种执行方式&#xff0c;一种是直接调用base_page中封装好的常用操作方法&#xff0c;另外一种是先调用baidu_homepage.py&#xff0c;通过baidu_homepage.py进行处理&#xff0c;再执行对应的案例&#xf…

MVC详解

模型&#xff0d;视图&#xff0d;控制器&#xff08;Modal View Controler&#xff0c;MVC&#xff09;是Xerox PARC在八十年代为编程语言Smalltalk&#xff0d;80发明的一种软件设计模式&#xff0c;至今已被广泛使用。最近几年被推荐为Sun公司J2EE平台的设计模式&#xff0c…

如何为每个URL连接设置自定义SSLSocketFactory的TrustManager

从javadoc中我们可以看到javax.net.ssl.HttpsURLConnection提供了一个静态方法来用setDefaultSSLSocketFory&#xff08;&#xff09;方法覆盖。 这样&#xff0c;您就可以提供一个自定义javax.net.ssl.TrustManager&#xff0c;它可以验证您自己的CA证书握手和验证等。但是&am…

ES6之命令妙用

很多人都听说过ES6&#xff08;也就是ECMAScript的新一代标准&#xff09;并且对她充满了向往&#xff0c;下面通过一个ES6中小知识点——let命令&#xff0c;来解开她的神秘面纱&#xff0c;让大家初步认识一下ES6的语法规范。let命令属于ES6中的一个基本语法&#xff0c;与原…

VUE-搜索过滤器

先看看效果 首先引入 <script src"https://cdn.jsdelivr.net/npm/vue"></script> HTML部分 <div id"app"><input v-modelsearch /><ul v-if"searchData.length > 0"><li v-for"item in searchData&quo…

使用spring-session外部化Spring-boot应用程序的会话状态

Spring-session是一个非常酷的新项目&#xff0c;旨在提供一种更简单的方法来管理基于Java的Web应用程序中的会话。 我最近在spring-session中探索的功能之一是它支持外部化会话状态的方式&#xff0c;而无需费心诸如Tomcat或Jetty之类的特定Web容器的内部。 为了测试spring-s…

windows2008 sp2 x64安装 ocs 2007 r2 笔记

在写这篇日志之前&#xff0c;反反复复安装了N次&#xff0c;重装操作系统好几次&#xff0c;为了让大家不再犯同样的错误&#xff0c;特留下几点要注意的&#xff1a; 1. 不要用windows2008 r2 装 ocs 2007 r2&#xff0c; 我很天真的下载了windows2008 r2 并开始装 ocs r2&am…

JS(JQEERY) 获取JSON对象中的KEY VALUE

var json { "Type": "Coding", "Height":100 };for (var key in json){alert(key); alert(json[key]);}$.each(json, function(i) {alert(json[i]);alert(i); }); 转载于:https://www.cnblogs.com/ytjjyy/archive/2012/04/17/2453340.html

vue 特定条件下绑定事件

今天写了个小功能&#xff0c;看起来挺简单&#xff0c;写的过程中发现了些坑。1.div没有disabled的属性&#xff0c;所以得写成button2.disabled在data时&#xff0c;默认是true&#xff0c;使得初始化时&#xff0c;默认置灰按钮&#xff0c;无法点击 <div classform-item…

使用纯HTML和OmniFaces构建动态响应的多级菜单

最近&#xff0c;我不得不使用JSF 2.2创建一个响应式多级菜单。 要求&#xff1a;菜单应&#xff1a; 从后端使用动态结构创建 反应灵敏&#xff0c;例如对桌面和移动设备友好 有带有导航链接的子菜单项 支持触摸事件 支持键盘辅助功能 PrimeFaces的菜单不是一个选择。 实…

Jquery 日历控件

非常好的Jquery日历控件 http://keith-wood.name/datepick.html 转载于:https://www.cnblogs.com/hubj/archive/2011/04/28/2031791.html