【Android - IPC】之AIDL简介
参考资料:
1、《Android开发艺术探索》第二章2.4.4
2、Android AIDL Binder框架解析:http://blog.csdn.net/lmj623565791/article/details/38461079
3、你真的理解AIDL中的in、out、inoutm么:http://www.open-open.com/lib/view/open1469494342021.html
4、慕课网《AIDL-小白成长记》
1、 AIDL简介
Android系统规定:每个应用程序独自拥有一份虚拟机,一个应用程序和另一个应用程序没有办法直接进行通信,这样保证了进程之内数据的安全性,也保证一个应用程序崩溃之后不会导致其他应用程序跟着崩溃。两个进程如果想要通信,只能通过Android系统底层进行通信。
AIDL(Android Interface Definition Language,Android接口定义语言)是Android中的一种IPC(Inter-Process Communication,跨进程通信)的方式,它允许我们编写一个接口,作为客户端和服务端通信的桥梁。AIDL是Android基于IDL自己定义的一种客户端和服务端交流的语言规范。
2、 AIDL使用方法
在这个章节中,我们通过一个实例学习AIDL的用法。
在这个实例中有服务端和客户端,服务端有操作Book的功能,客户端调用服务端的功能。
由于Book不是基本数据类型,因此想要让Book在多进程之间传递,需要对Book进行序列化,代码如下:
package my.itgungnir.aidl; import android.os.Parcel;
import android.os.Parcelable; /**
* Book实体类
*/
public class Book implements Parcelable {
private String booName;
private int pirce; public Book(String booName, int pirce) {
this.booName = booName;
this.pirce = pirce;
} protected Book(Parcel in) {
booName = in.readString();
pirce = in.readInt();
} public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
} @Override
public Book[] newArray(int size) {
return new Book[size];
}
}; @Override
public int describeContents() {
return 0;
} @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(booName);
dest.writeInt(pirce);
}
}
我们的思路是:在服务端中定义操作Book列表的方法(添加书籍、查询所有书籍),然后在客户端中远程调用服务端的这两个方法操作书籍。
下面提供这个实例的编写代码和详细说明。
2.1、 AIDL接口的创建
首先来介绍一下AIDL接口的定义语法:
1、AIDL文件支持的数据类型:
(1)基本数据类型(int、long、char、boolean、double等);
(2)String和CharSequence;
(3)List:只支持ArrayList,里面每个元素必须都能够被AIDL支持;
(4)Map:只支持HashMap,里面的每个元素必须都能够被AIDL支持,包括key和value;
(5)Parcelable:所有实现了Parcelable接口的对象;
(6)AIDL:所有的AIDL接口本身也可以在AIDL文件中使用。
2、自定义的Parcelable对象和AIDL对象必须要显式import进来,不管它们是否和当前的AIDL文件位于同一个包内。
3、如果AIDL文件中用到了自定义的Parcelable对象,那么必须重新建一个和它同名的AIDL文件,并在其中声明它为Parcelable类型。
4、AIDL接口的方法中,除了基本类型的参数,其他类型的参数都必须标上数据流向:in表示数据只能从客户端流向服务端;out表示数据只能从服务端流向客户端;inout表示数据可以在服务端和客户端之间双向流通。注意:基本数据类型默认且只能是in流向。
5、AIDL接口中只支持方法,不支持声明静态常量。
6、AIDL的包结构在服务端和客户端要保持一致,否则运行会出错,这是因为客户端需要反序列化服务端中和AIDL接口相关的所有类,如果类的完整路径不一样的话,就无法完成反序列化,程序也就无法正常运行。
接下来我们来创建一个AIDL接口IBookManager.aidl,其中用到了Book类,因此我们还需要创建一个Book.aidl文件。
Book.aidl文件中的代码如下:
package my.itgungnir.aidl; parcelable Book;
IBookManager.aidl文件中的代码如下:
package my.itgungnir.aidl; import my.itgungnir.aidl.Book; interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
可以看到,这两个AIDL文件中的语法完全遵循上面说的AIDL语法。
2.2、 服务端的实现
定义了AIDL接口之后,我们就可以实现这个接口了。创建一个Service类BookManagerService,代码如下:
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable; import java.util.ArrayList;
import java.util.List; import my.itgungnir.aidl.Book;
import my.itgungnir.aidl.IBookManager; /**
* 定义服务端Service,实现AIDL接口
*/
public class BookManagerService extends Service {
private CopyOnWriteArrayList<Book> bookList = new CopyOnWriteArrayList<>(); private Binder binder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return bookList;
} @Override
public void addBook(Book book) throws RemoteException {
bookList.add(book);
}
}; @Override
public void onCreate() {
super.onCreate();
bookList.add(new Book("Android", 20));
bookList.add(new Book("iOS", 17));
} @Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
在这个类中,我们创建了一个Stub的对象,在这个对象的两个方法中进行数据的处理,最后在onBind()方法中返回这个Stub。
编写这个类的时候需要注意:这个类中我们并没有使用ArrayList,而是一个CopyOnWriteArrayList类(这个类并不继承自ArrayList)。这个CopyOnWriteArrayList支持是一种支持并发读/写的List。由于AIDL是在服务端的Binder线程池中执行的,因此当多个客户端同时连接的时候,会存在多个线程同时访问的情形,所以我们要在AIDL方法中处理线程同步,而CopyOnWriteArrayList可以自动进行线程同步。
另外,前面说道,AIDL中只支持ArrayList,但CopyOnWriteArrayList并不继承自ArrayList,为什么AIDL还是会支持呢?这是因为AIDL中所支持的是抽象的List,而List只是一个接口,因此虽然服务端返回的是CopyOnWriteArrayList,但是在Binder中会按照List的规范去访问数据并最终形成一个新的ArrayList传递给客户端。和这个类类似的是Map中的ConcurrentHashMap。
编写完了Service类,我们需要在Manifest文件中注册这个Service,代码如下:
<service android:name=".BookManagerService">
<intent-filter>
<action android:name="my.itgungnir.aidl.book_server" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
至此,服务端的代码就编写完成了。
2.3、 客户端的实现
在客户端,我们先要绑定服务端的服务,将服务端返回的Binder接口转换成AIDL接口,然后就可以调用服务端的方法了。
需要注意的是,AIDL文件和AIDL中用到的Parcelable类,在服务端和客户端都需要有一份,且包路径必须一致。
客户端的MainActivity中的代码如下:
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log; import java.util.List; import my.itgungnir.aidl.Book;
import my.itgungnir.aidl.IBookManager; public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity"; private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager manager = IBookManager.Stub.asInterface(service);
try {
// 查询所有图书
List<Book> bookList = manager.getBookList();
Log.i(TAG, "query book list: " + bookList.toString());
// 添加新书
Book newBook = new Book("Html", 40);
manager.addBook(newBook);
Log.i(TAG, "add book: " + newBook.toString());
// 查询所有图书
bookList = manager.getBookList();
Log.i(TAG, "query book list: " + bookList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
} @Override
public void onServiceDisconnected(ComponentName name) {
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setAction("my.itgungnir.aidl.book_server");
intent.setPackage("my.itgungnir.server");
bindService(intent, connection, Context.BIND_AUTO_CREATE);
} @Override
protected void onDestroy() {
unbindService(connection);
super.onDestroy();
}
}
由于这里把服务端和客户端放在两个不同的Module中,因此需要为Intent对象设置package属性为服务端的包名。
可以看到,在客户端,我们调用了服务端的getBookList()方法,将存储在服务端List中的Book对象获取过来,并通过Log日志打印到控制台。这样,就可以在控制台中看到我们打印出来的信息了,如下:
my.itgungnir.client I/MainActivity: query book list: [Book{booName='Android', pirce=20}, Book{booName='iOS', pirce=17}]
my.itgungnir.client I/MainActivity: add book: Book{booName='Html', pirce=40}
my.itgungnir.client I/MainActivity: query book list: [Book{booName='Android', pirce=20}, Book{booName='iOS', pirce=17}, Book{booName='Html', pirce=40}]
【Android - IPC】之AIDL简介的更多相关文章
- android IPC及原理简介
什么是Android操作系统,所谓的Android:是基于Linux内核的软件平台和操作系统,早期由Google开发,后由开放手机联盟Open Handset Alliance)开发. Linux ...
- android service 的各种用法(IPC、AIDL)
http://my.oschina.net/mopidick/blog/132325 最近在学android service,感觉终于把service的各种使用场景和用到的技术整理得比较明白了,受益颇 ...
- Android IPC通信和AIDL技术应用
首先我们了解一下 IPC和AIDL IPC:进程间通信 AIDL:Android Interface Definition Language,即Android接口定义语言. 为什么使用: Androi ...
- Android IPC机制(三)在Android Studio中使用AIDL实现跨进程方法调用
在上一篇文章Android IPC机制(二)用Messenger进行进程间通信中我们介绍了使用Messenger来进行进程间通信的方法.可是我们能发现Messenger是以串行的方式来处理client ...
- 【Android - IPC】之Binder机制简介
参考资料: 1.<Android开发艺术探索>第二章2.3.3 Binder 2.[Android Binder设计与实现-设计篇] 3.[Android Binder机制介绍] 1. 什 ...
- android IPC通信(上)-sharedUserId&&Messenger
看了一本书,上面有一章解说了IPC(Inter-Process Communication,进程间通信)通信.决定结合曾经的一篇博客android 两个应用之间的通信与调用和自己的理解来好好整理总结一 ...
- Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- ApiWrapper
前面两片文章讲解了通过AIDL和Messenger两种方式实现Android IPC.而本文所讲的并不是第三种IPC方式,而是对前面两种方式进行封装,这样我们就不用直接把Aidl文件,java文件拷贝 ...
- Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- Messenger
Messenger类实际是对Aidl方式的一层封装.本文只是对如何在Service中使用Messenger类实现与客户端的通信进行讲解,对Messenger的底层不做说明.阅读Android Prog ...
- Android 中的AIDL,Parcelable和远程服务
Android 中的AIDL,Parcelable和远程服务 早期在学习期间便接触到AIDL,当时对此的运用也是一撇而过.只到近日在项目中接触到AIDL,才开始仔细深入.AIDL的作用 ...
随机推荐
- SpringBootCLI 命令行工具
Spring Boot CLI 是用于快速开发 Spring 应用的命令行工具.用来运行 Groovy (与 Java 风格类似)脚本. spring-cli 似乎不是可以各种diy spring-b ...
- linux安装redis及外网访问
1.下载Redis,最新版是redis-3.2.1.tar.gz 2.上传到Linux上,解压到/usr/local/下面 ,命令:tar -zxvf redis-3.2.1.tar.gz 3.我们 ...
- Chrome插件开发(三)
在日常工作中,我们可能经常需要在手机端测试我们所做的页面,如果每次在手机端测试都手输网址,网址短的还好,如果长的网址也需要一个字母一个字母去敲,那无疑是一场噩梦,试想我们有一个工具只需要点击一个按钮就 ...
- 微信授权就是这个原理,Spring Cloud OAuth2 授权码模式
上一篇文章Spring Cloud OAuth2 实现单点登录介绍了使用 password 模式进行身份认证和单点登录.本篇介绍 Spring Cloud OAuth2 的另外一种授权模式-授权码模式 ...
- 数竞大佬jhc的三角函数复习题
班主任让数竞大佬jhc整理的三角函数复习题,我参与编辑完成.个别题目来自参考书.度盘pdf格式下载:复习题提取码419d,答案提取码5a12 "单纯"的运算 本文由蒋浩川原创,由\ ...
- [考试反思]NOIP模拟测试19:洗礼
[]260 []230[]210 []200[8]170[9]160 这套题一般,数据很弱,T1T2暴力都能A,而且都是一些思维题,想不到就爆0. 原因不明,很多一直很强的人在这一次滑铁卢了,于是我个 ...
- hexo搭建简易的博客网站
0.环境检测 1.系统升级(图形更新) #update-manager 检测状态 2.检测升级(命令更新) #sudo apt update #sudo apt -y dist-upgrade 一.安 ...
- Eclipse搭建Android开发环境并运行Android项目
Eclipse搭建Android开发环境并运行Android项目 (详细) 安装环境: window 10 64位 安装工具: JDK.Eclipse.SDK.ADT 安装步骤: 1.JAVA JDK ...
- jsoup爬虫实战心得
1.heder很重要,一切尽在header中.尤其cookie,useragent. 2.对于加密的连接,查看js加密过程并试着通过java或你正在使用的语言去实现 3.查看在跳转之前前端发起的关键请 ...
- 如何给HTML标签中的文本设置修饰线
text-decoration属性介绍 text-decoration属性是用来设置文本修饰线呢,text-decoration属性一共有4个值. text-decoration属性值说明表 值 作用 ...