AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。

AIDL的设计是为了实现进程间通信,如同两个进程的桥梁,传输一些特定规格的数据。

Android中实现进程通信的几种方式:

1、Activity (借助Intent调用其他APP的Activity实现跨进程通信)

2、广播接收者(BroadcastReceiver)

3、内容提供者(ContentProvider)

4、AIDL(Android Interface definition language,Android接口定义语言)

AIDL特殊的语法:

文件类型:用AIDL书写的文件的后缀是 .aidl,而不是 .java。

数据类型:

  默认支持的数据类型包括:

  • Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。
  • String 类型。
  • CharSequence类型。
  • List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable(下文关于这个会有详解)。List可以使用泛型。
  • Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。Map是不支持泛型的。
  • 定向tag:AIDL中的定向 tag 表示了在跨进程通信中数据的流向,其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。

两种AIDL文件:一类是用来定义parcelable对象,以供其他AIDL文件使用AIDL中非默认支持的数据类型的。一类是用来定义方法接口,以供系统使用来完成跨进程通信的。

AIDL实现跨进程通信:

1、使数据实现Parcelable接口

  客户端传入服务端的对象需要经过序列化操作,将数据转化为序列化流传到服务端,再由服务端进行反序列化获取数据。AIDL中实现序列化的方式是实现Parcelable接口。如果是默认支持数据类型则无需进行序列化操作。

  in的定向Tag方法为writeToParcel() ,out的定向Tag方法为 readFromParcel()

package com.lypeer.ipcclient;

import android.os.Parcel;
import android.os.Parcelable; /**
* Book.java
*
* Created by lypeer on 2016/7/16.
*/
public class Book implements Parcelable{
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getPrice() {
return price;
} public void setPrice(int price) {
this.price = price;
} private String name;
private int price;
public Book(){} public Book(Parcel in) {
name = in.readString();
price = 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(name);
dest.writeInt(price);
} /**
* 参数是一个Parcel,用它来存储与传输数据
* @param dest
*/
public void readFromParcel(Parcel dest) {
//注意,此处的读值顺序应当是和writeToParcel()方法中一致的
name = dest.readString();
price = dest.readInt();
} //方便打印数据
@Override
public String toString() {
return "name : " + name + " , price : " + price;
}
}

2、新建AIDL文件

// Book.aidl
//第一类AIDL文件
//这个文件的作用是引入了一个序列化对象 Book 供其他的AIDL文件使用
//注意:Book.aidl与Book.java的包名应当是一样的
package com.lypeer.ipcclient; //注意parcelable是小写
parcelable Book;
// BookManager.aidl
//第二类AIDL文件
//作用是定义方法接口
package com.lypeer.ipcclient;
//导入所需要使用的非默认支持数据类型的包
import com.lypeer.ipcclient.Book; interface BookManager { //所有的返回值前都不需要加任何东西,不管是什么数据类型
List<Book> getBooks(); //传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定
void addBook(in Book book);
}

  Book.aidl与Book.java的包名应当是一样的。这似乎理所当然的意味着这两个文件应当是在同一个包里面的,然而在 Android Studio如果这样做的话,系统根本就找不到 Book.java 文件,两种解决方法如下:

(1)修改 build.gradle 文件:在 android{} 中间加上下面的内容:

sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/main/aidl']
}
}

(2)把 java 文件放到 java 包下去:把 Book.java 放到 java 包里任意一个包下,保持其包名不变,与 Book.aidl 一致。

3、复制相关文件

  将在一端的AIDL文件写完后,复制到另一端。(一般情况是服务端写好复制到客户端)

4、编写服务端代码

/**
* 服务端的AIDLService.java
* <p/>
* Created by lypeer on 2016/7/17.
*/
public class AIDLService extends Service { public final String TAG = this.getClass().getSimpleName(); //包含Book对象的list
private List<Book> mBooks = new ArrayList<>(); //由AIDL文件生成的BookManager
private final BookManager.Stub mBookManager = new BookManager.Stub() {
@Override
public List<Book> getBooks() throws RemoteException {
synchronized (this) {
Log.e(TAG, "invoking getBooks() method , now the list is : " + mBooks.toString());
if (mBooks != null) {
return mBooks;
}
return new ArrayList<>();
}
} @Override
public void addBook(Book book) throws RemoteException {
synchronized (this) {
if (mBooks == null) {
mBooks = new ArrayList<>();
}
if (book == null) {
Log.e(TAG, "Book is null in In");
book = new Book();
}
//尝试修改book的参数,主要是为了观察其到客户端的反馈
book.setPrice(2333);
if (!mBooks.contains(book)) {
mBooks.add(book);
}
//打印mBooks列表,观察客户端传过来的值
Log.e(TAG, "invoking addBooks() method , now the list is : " + mBooks.toString());
}
}
}; @Override
public void onCreate() {
super.onCreate();
Book book = new Book();
book.setName("Android开发艺术探索");
book.setPrice(28);
mBooks.add(book);
} @Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(getClass().getSimpleName(), String.format("on bind,intent = %s", intent.toString()));
return mBookManager;
}
}

代码分为三个部分:

  第一块是初始化。在 onCreate() 方法里面我进行了一些数据的初始化操作。
  第二块是重写 BookManager.Stub 中的方法。在这里面提供AIDL里面定义的方法接口的具体实现逻辑。
  第三块是重写 onBind() 方法。在里面返回写好的 BookManager.Stub 。

在 AndroidManifest 文件里面注册这个我们写好的 Service。(必须)

<service
android:name=".service.AIDLService"
android:exported="true">
<intent-filter>
<action android:name="com.lypeer.aidl"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>

5、编写客户端代码

public class AIDLActivity extends AppCompatActivity {

    //由AIDL文件生成的Java类
private BookManager mBookManager = null; //标志当前与服务端连接状况的布尔值,false为未连接,true为连接中
private boolean mBound = false; //包含Book对象的list
private List<Book> mBooks; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl);
} /**
* 按钮的点击事件,点击之后调用服务端的addBookIn方法
*
* @param view
*/
public void addBook(View view) {
//如果与服务端的连接处于未连接状态,则尝试连接
if (!mBound) {
attemptToBindService();
Toast.makeText(this, "当前与服务端处于未连接状态,正在尝试重连,请稍后再试", Toast.LENGTH_SHORT).show();
return;
}
if (mBookManager == null) return; Book book = new Book();
book.setName("APP研发录In");
book.setPrice(30);
try {
mBookManager.addBook(book);
Log.e(getLocalClassName(), book.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
} /**
* 尝试与服务端建立连接
*/
private void attemptToBindService() {
Intent intent = new Intent();
intent.setAction("com.lypeer.aidl");
intent.setPackage("com.lypeer.ipcserver");
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
} @Override
protected void onStart() {
super.onStart();
if (!mBound) {
attemptToBindService();
}
} @Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mServiceConnection);
mBound = false;
}
} private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(getLocalClassName(), "service connected");
mBookManager = BookManager.Stub.asInterface(service);
mBound = true; if (mBookManager != null) {
try {
mBooks = mBookManager.getBooks();
Log.e(getLocalClassName(), mBooks.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
} @Override
public void onServiceDisconnected(ComponentName name) {
Log.e(getLocalClassName(), "service disconnected");
mBound = false;
}
};
}

参考文章:http://www.jianshu.com/p/a8e43ad5d7d2

AIDL初识的更多相关文章

  1. Android探索之AIDL实现进程间通信

    前言: 前面总结了程序间共享数据,可以使用ContentProvider也可以使用SharedPreference,那么进程间怎么共享内存呢?Android系统中的进程之间不能共享内存,因此,需要提供 ...

  2. Android动画效果之初识Property Animation(属性动画)

    前言: 前面两篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画).Frame Animation(逐帧动画)Andr ...

  3. 初识Hadoop

    第一部分:              初识Hadoop 一.             谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...

  4. python学习笔记(基础四:模块初识、pyc和PyCodeObject是什么)

    一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...

  5. 了解AIDL

    1.什么是AIDL? Android Interface Definition Lauguage(android接口描述语言)是一个IDL语言. 2.AIDL的作用? 背景:在android平台 中, ...

  6. 初识IOS,Label控件的应用。

    初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...

  7. Android开发aidl使用中linkToDeath和unlinkToDeath的使用

    1.Binder死亡代理     这一节首先将介绍Binder类中比较重要的两个方法linkToDeath和unlinkToDeath.我们知道Binder是运行在服务进程,若服务端进程因为某种原因“ ...

  8. UI篇(初识君面)

    我们的APP要想吸引用户,就要把UI(脸蛋)搞漂亮一点.毕竟好的外貌是增进人际关系的第一步,我们程序员看到一个APP时,第一眼就是看这个软件的功能,不去关心界面是否漂亮,看到好的程序会说"我 ...

  9. android不需要Socket的跨进程推送消息AIDL!

    上篇介绍了跨进程实时通讯http://www.cnblogs.com/xiaoxiaing/p/5818161.html 但是他有个缺点就是服务端无法推送消息给客户端,今天这篇文章主要说的就是服务器推 ...

随机推荐

  1. RMAN中format的参数

    (转自:http://blog.chinaunix.net/uid-23079711-id-2554290.html) format 的替换变量,注意大小写! 1.     %d --数据库的db_n ...

  2. Hrbust 1535 相爱

    Description 静竹在斐波那契的帮助下,渐渐的和数学相爱了.和数学在一起最有意思的就是它能够出一些特别有意思并且巧妙的题目让静竹来思考.这次也不例外,给静竹两个数a,b,又给出了加,减,乘,除 ...

  3. 【css】响应式布局入门【转】

    最近研究响应式设计框架的时候,发现网上很多相关的属性介绍,却很少有系统的入门级使用的文章,我自己整理了一篇入门知识,并没有什么高深的理论,也不牵扯到框架. 目前已经越来越多的站点以及wap站点使用响应 ...

  4. LeetCode之Longest Substring Without Repeating Characters

    [题目描述] Given a string, find the length of the longest substring without repeating characters. Exampl ...

  5. Ubuntu 中sendmail 的安装、配置与发送邮件的具体实现

    一.安装 ubuntu中sendmail函数可以很方便的发送邮件,ubuntu sendmail先要安装两个包. 必需安装的两个包: 代码  sudo apt-get install sendmail ...

  6. 你必须了解的Session的本质

    http://netsecurity.51cto.com/art/201402/428721.htm Cookie和session由于实现手段不同,因此也各有优缺点和各自的应用场景: 1.   应用场 ...

  7. 【Shell脚本】逐行处理文本文件

    经常会对文体文件进行逐行处理,在Shell里面如何获取每行数据,然后处理该行数据,最后读取下一行数据,循环处理.有多种解决方法如下: 1.通过read命令完成. read命令接收标准输入,或其他文件描 ...

  8. ssm框架实现图片上传显示并保存地址到数据库

    本案例是通过springmvc+spring+mybatis框架以商品上传为例,实现的图片上传功能,并把图片的地址保存到数据库并在前台显示上传的图片. 本项目是使用maven搭建的项目,首先看下项目结 ...

  9. 体验 k8s 的核心功能

    快速体验 k8s 的核心功能:应用部署.访问.Scale Up/Down 以及滚动更新 https://yq.aliyun.com/articles/337209?spm=a2c4e.11153940 ...

  10. iOS 信号量解决-网络异步请求的数据同步返回问题

    有那么一个场景如下 +PayWithBlock:(NSString*(^)(NSString *message)) block; 如果 block 返回是同步的那是没有问题的,但是如果block 内容 ...