大话android 进程通信之AIDL
上一篇的service涉及到进程通信问题,主要解决办法是通过 messenger来发送消息,这也是Google推荐的进程通信方式,比较简单易懂嘛~~,messenger底层也是通过binder来实现的,对于binder,这里就不做介绍了。但是如果允许不同应用的客户端用 IPC 方式访问服务、在服务中处理多线程就不太适合了,还是得乖乖用AIDL,AIDL这玩意,估计不少人都会有点陌生吧,接来下就通过跨应用对书本进行增删查,来讲解如何通过AIDL实现 跨进程通信。
一、定义AIDL接口
在开始设计 AIDL 接口之前,要注意 AIDL 接口的调用是直接函数调用。不应该假设发生调用的线程。视调用来自本地进程还是远程进程中的线程,实际情况会有所差异。具体而言:
- 来自本地进程的调用在发起调用的同一线程内执行。如果该线程是主 UI 线程,则该线程继续在 AIDL 接口中执行。如果该线程是其他线程,则其便是在服务中执行代码的线程。因此,只有在本地线程访问服务时,我们才能完全控制哪些线程在服务中执行(但如果真是这种情况,根本不应该使用 AIDL,而是应该通过实现 Binder 类创建接口)。
- 来自远程进程的调用分派自平台在自有进程内部维护的线程池。必须为来自未知线程的多次并发传入调用做好准备。换言之,AIDL 接口的实现必须是完全线程安全实现。
oneway
关键字用于修改远程调用的行为。使用该关键字时,远程调用不会阻塞;它只是发送事务数据并立即返回。接口的实现最终接收此调用时,是以正常远程调用形式将其作为来自Binder 线程池的常规调用进行接收。如果oneway
用于本地调用,则不会有任何影响,调用仍是同步调用。
package com.example.aidl;
import com.example.aidl.Book;interface IBookManager {List<Book> getBookList();void addBook(in Book book);boolean removeBook(in Book book);
}
在AIDl文件中可以使用的数据类型有:
- Java 编程语言中的所有原语类型(如
int
、long
、char
、boolean
等等) String
CharSequence
List
List
中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。可选择将List 用作“通用”类(例如,List<String>
)。另一端实际接收的具体类始终是ArrayList
,但生成的方法使用的是List
接口。Map
Map
中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。不支持通用 Map(如Map<String,Integer>
形式的 Map)。另一端实际接收的具体类始终是HashMap
,但生成的方法使用的是Map
接口。
package com.example.aidl;
parcelable Book;
转到Java目录下,在相同的包下创建一个book对象,并使其实现Parcelable接口(AIDL要求接口中的类必须要实现Parcelable接口,并在AIDL目录下声明该类为parcelable,如上所示)
public class Book implements Parcelable {public int bookId;public String bookName;public Book(int bookId, String bookName) {this.bookId = bookId;this.bookName = bookName ;}private Book(Parcel parcel){bookId = parcel.readInt();bookName = parcel.readString() ;}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(bookId);dest.writeString(bookName);}public static final Creator<Book> CREATOR = new Creator<Book>(){@Overridepublic Book createFromParcel(Parcel parcel) {return new Book(parcel);}@Overridepublic Book[] newArray(int i) {return new Book[i];}};
}
关键来了!!(敲黑板) 准备工作做完后,我们就可以生成相应的binder类了,选择build->make project即可,gradle会自动帮我们创建一个IBookManager的Java接口,生成的接口包括一个名为 Stub 的子类,这个子类是其父接口(例如,IBookManager.Stub)的抽象实现,用于声明 .aidl 文件中的所有方法。
二、实现AIDL接口
private Binder binder = new IBookManager.Stub(){@Overridepublic List<Book> getBookList() throws RemoteException {return null;}@Overridepublic void addBook(Book book) throws RemoteException {}@Overridepublic boolean removeBook(Book book) throws RemoteException {return false ;}};
现在,binder 是 Stub
类的一个实例,用于定义服务的 RPC 接口。在下一步中,将向客户端公开该实例,以便客户端能与服务进行交互。
在实现 AIDL 接口时应注意遵守以下这几个规则:
- 由于不能保证在主线程上执行传入调用,因此一开始就需要做好多线程处理准备,并将服务正确地编译为线程安全服务。
- 默认情况下,RPC 调用是同步调用。如果明知服务完成请求的时间不止几毫秒,就不应该从Activity的主线程调用服务,因为这样做可能会使应用挂起(Android可能会显示“Application is Not Responding”对话框)— 我们通常应该从客户端内的单独线程调用服务。
- 在跨进程通信引发的任何异常都不会回传给调用方。
三、向client端公开该接口
@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG, "onBind: ");return binder;}
现在,当客户端(如 Activity)调用 bindService() 以连接此服务时,客户端的 onServiceConnected() 回调会接收服务的 onBind() 方法返回的 binder实例。
最后我们在配置文件中声明该service,并设置其可以被其他应用调用
<service android:name="com.example.aidl.BookManagerService"android:enabled="true"android:exported="true" />
至此,service端的准备工作就基本完成了,再来看看client端的
四、client端的实现
我们来看 MainActivity,先是绑定service端的服务
public void bindService(View view){Intent intent = new Intent() ;intent.setComponent(newComponentName("com.ujs.service","com.example.aidl.BookManagerService"));bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);}
这里我们用到intent.setComponent()方法,这是Android为了方便启动其他应用的组件而提供的,ComponentName有两个参数,第一个是目标应用的包名,第二个参数是目标组件的详细路径,然后我们传入一个serviceconnection,在onServiceConnected方法中获取service端的接口,这样我们就可以愉快的通过这个接口与service通信了
private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.i(TAG, "onServiceConnected: - ");iBookManager = IBookManager.Stub.asInterface(service);try {List<Book> list = iBookManager.getBookList();for(Book b:list){Log.i(TAG, "onServiceConnected: "+b.bookName);Log.i(TAG, "onServiceConnected: "+b.bookId);}} catch (Exception e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {Log.i(TAG, "onServiceDisconnected: ");}};
我们可以通知service添加一本书
public void addBook(View view){try {Book web = new Book(1,"web App");iBookManager.addBook(web);Log.i(TAG, "addBook: "+web.toString());Log.i(TAG, "addBook: 添加数据了");} catch (RemoteException e) {e.printStackTrace();}}
从service端获取所有书本信息
public void upDate(View view){try {List<Book> list = iBookManager.getBookList();for(Book book : list){Log.i(TAG, "\nbook name : "+book.bookName+" book id :"+book.bookId);}} catch (RemoteException e) {e.printStackTrace();}}
通知service端删除一本书,并获取返回值
public void remove(View view){try {boolean b = iBookManager.removeBook(web);if(b)Log.i(TAG, "remove: service 删除数据了");elseLog.i(TAG, "remove: 删除失败了");} catch (RemoteException e) {e.printStackTrace();}}
至此,基于AIDL进程通信就打通了,掌握这些就满足基本的进程通信需求了~~
大话android 进程通信之AIDL相关推荐
- Android跨进程通信二——AIDL
AIDL全称Android Interface Definition Language即安卓接口定义语言.主要用于多进程通信.比Messenger,它具有支持多线程优势 注意事项: 为了线程安全考虑, ...
- android进程通信6,[Android]你不知道的Android进程化(6)--进程通信Andromeda框架
近来看到爱奇艺发布了多进程的架构框架Andromeda.研究一下其多进程的通信方式. 具体github地址 通过此框架的初步分析 1.通过grade插件完善AndroidManifest.xml配置文 ...
- [Android]进程通信Andromeda框架
作者:苍王 时间:2018.6.1 以下是我这个系列的相关文章,有兴趣可以参考一下,可以给个喜欢或者关注我的文章. [Android]如何做一个崩溃率少于千分之三噶应用app--章节列表 组件化群1已 ...
- [Android]你不知道的Android进程化(4)--进程通信AIDL框架
Google爸爸,听说要将一些插件化hook系统的变量属性禁用,Android P之后很可能将会不再有插件化.热更新.主题变换.资源加固等骚操作.试图hook,你将会看到 NoSuchFieldExc ...
- Android跨进程通信Binder机制与AIDL实例
文章目录 进程通信 1.1 进程空间划分 1.2 跨进程通信IPC 1.3 Linux跨进程通信 1.4 Android进程通信 Binder跨进程通信 2.1 Binder简介 2.2 Binder ...
- Android 进阶8:进程通信之 Binder 机制浅析
读完本文你将了解: IBinder Binder Binder 通信机制 Binder 驱动 Service Manager Binder 机制跨进程通信流程 Binder 机制的优点 总结 Than ...
- Android之解决aidl里面函数参数太大不能跨进程通信的问题
问题: 因为做的截屏拍照是跨进程通信的,所以需要用aidl,但是参数传递用的byte[] image,网上查了下aidl传递的基本参数类型,没有byte[], 然后把图片转化成String,结果时候接 ...
- Android笔记 使用AIDL和远程服务实现进程通信
简介 AIDL(Android Interface Definition Language:接口定义语言) 在Android中, 每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实 ...
- Android R版本 MtkSettings和Telephony进程通信aidl
需要获取simunlockstate状态,而这个不由我们这边控制,在免于提Mtk case的情况下,通过Telephony获取这个值,telephony是个服务apk,不能通过android.bp引入 ...
最新文章
- 绘制电路图风格的纠结
- Android提高十六篇之使用NDK把彩图转换灰度图
- 深度探索C++ 对象模型(3)-默认构造函数Default Constructor
- docker 修改容器的主机名
- select隐藏_数仓|几种SQL隐藏的错误,你遇到过吗?
- Storyboard的简单使用
- GCD Game HDU - 7061
- struts2异常处理流程_Struts2异常处理示例教程
- 13.TCP/IP 详解卷1 --- IGMP : Internet 管理组协议
- redis的其他功能
- 基于SSM的旅游管理系统
- 国际国内资管分仓跟单软件的具体作用
- 【LeetCode】马三来刷题之 Single Number
- 抽象代数 04.01 群的生成元组
- ASUS AC88U 路由器开机自启方法
- jQuery菜鸟教程02
- 有一间计算机实验室英语怎么说,实验室英语怎么说
- GRBL二:串口控制命令及代码解析(转载)
- java 药店管理系统_java药店管理平台
- 不知道视频如何裁剪画面大小不变?来看看这篇文章
热门文章
- oracle之分析函数 开窗函数,Oracle之分析函数、开窗函数
- uipath sequence传递参数_多孔材料测试及声学参数识别(中)_多孔材料声学参数正向识别...
- mysql 同步 存储过程_mysql 存储过程 实现数据同步
- 深度学习 英文 训练阶段_半监督深度学习训练和实现小Tricks
- linux 子系统 巡检,Linux 系统巡检
- mysql 安装更改目录权限设置密码_mysql-8.0 安装教程(自定义配置文件,密码方式已修改)...
- gitee使用svn_Gitee SVN支持
- 11、计算机图形学——几何(贝塞尔曲线与曲面)
- yolov5检测完不显示框和标注
- python中pygal_Python数据可视化之Pygal图表类型