莫问天涯路几重,轻衫侧帽且从容。这篇文章主要讲述Android开发——进程间通信之AIDL相关的知识,希望能为你提供帮助。
0.前言
不论是android还是其他操作系统,
都会有自己的IPC机制,
所谓IPC(
Inter-Process Communication)
即进程间通信。首先线程和进程是很不同的概念,
线程是CPU调用的最小单元,
进程一般在PC和移动设备上指一个程序或者一个应用,
一个进程可以包含多个线程。
IPC方式有很多,
在Android中常用的IPC方式包括Bundle、文件、Messenger、AIDL、ContentProvider和Socket等方式Android开发——进程间通信之AIDL(
一)
中介绍了AIDL的一个简单的用法,
本篇主要讲解使用AIDL传递自定义对象的方式。
【Android开发——进程间通信之AIDL】1.序列化
aidl文件定义的接口支持的数据类型如下:
//1.java的八种基本数据类型(
byte,
int,
short,
long,
float,
double,
char,
boolean)
//2.String
//3.CharSequence
//4.List,
List中所有的元素必须是aidl文件支持的数据类型,
例如List<
String>
//5.Map,
Map中所有的元素必须是aidl文件支持的数据类型,
//6.其他aidl定义的接口,
要手动添加import
//7.其他aidl文件中申明的类,
要手动添加import
在Android开发——进程间通信之AIDL( 一) 中的远程加法器中, 我们传递的就是int型数据, 这篇主要介绍最后一种, 其他aidl文件中申明的类, 这个类可以是自定义的类, 因此传递的数据类型组合更加自由。但是自定义的类要完成IPC必须要序列化, 序列化有Serializable和Parcelable两种方法, 后者是Android中的序列化方式, 因此效率更高, 但是使用起来比较麻烦。
先看一下完整工程的目录结构:
文章图片
Person.java就是我们自定义的类。我们要实现的目的就是跨进程传递该对象的内容。首先实现该类的序列化。
package com.example.ipc_aidl_obj;
/**
* Java Bean
* Created by SEU_Calvin on 2017/3/25.
*/
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable{
private String name;
private int age;
public Person(String name, int age){
this.name =
name;
this.age =
age;
}
//从Parcel中读出之前写进的数据
protected Person(Parcel in) {
this.name =
in.readString();
this.age =
in.readInt();
}
public static final Parcelable.Creator<
Person>
CREATOR =
new Parcelable.Creator<
Person>
() {
//反序列化,
把我们通过writeToParcel方法写进的数据再读出来
@
Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@
Override
public Person[] newArray(int size) {
return new Person[size];
}
};
public String getName() {
return name;
}
public void setName(String name) {
this.name =
name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age =
age;
}
//实现 Parcelable 接口所需重写的方法1,
一般不用管
@
Override
public int describeContents() {
return 0;
}
//实现 Parcelable 接口所需重写的方法2,
将对象的每个字段写入到Parcel中
@
Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
}
@
Override
public String toString() {
return "
Person{"
+
"
name=
'
"
+
name +
'
\\'
'
+
"
, age=
"
+
age +
'
}'
;
}
}
我们的Person类实现了Parcelable接口, 覆写了接口中describeContents()、writeToParcel() 的两个方法, 前者返回当前对象的内容描述, 如果有描述符则返回1, 绝大多数情况要返回0。后者将对象写入序列化结构中。通过查看文档我们发现Parcel是没有writeShort()这个方法的, 这也正是AIDL无法传递short类型的数据的原因。然后就是静态创建构造器CREATOR, 注意要加final修饰且名字必须为CREATOR不能更改, 其中createFromParcel()用于把我们之前写进Parcel中的数据在读出来。这里要注意的是哪个字段先写进去, 就先读取哪个字段。这样我们自定义的实体类就序列化好了, 以备后续使用。
2.创建AIDL文件
共有两个AIDL文件, 一个是我们自定义对象的声明, 一个是接口声明。在后者中需要将前者显式的import进来。
// IPersonn.aidl
package com.example.ipc_aidl_obj;
// Declare any non-default types here with import statements
parcelable Person;
// IGetData.aidl
package com.example.ipc_aidl_obj;
// Declare any non-default types here with import statements
import com.example.ipc_aidl_obj.Person;
interface IGetData{
List<
Person>
getPersonList(in Person person);
}
接口中的getPersonList()方法将客户端传来的Person对象放入List中并返回List中全部的对象, 这里需要说一下的就是getPersonList()方法中的in关键字, 即数据的走向, 有in/out/inout三种类型。根据需求选择合适的的数据走向类型。
3.实现接口
package com.example.ipc_aidl_obj;
/**
* 服务端
* Created by SEU_Calvin on 2017/3/25.
*/
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class IRemoteService extends Service {
List<
Person>
persons;
@
Nullable
@
Override
public IBinder onBind(Intent intent) {
persons =
new ArrayList<
>
();
return iBinder;
}private IBinder iBinder =
new IGetData.Stub() {
@
Override
public List<
Person>
getPersonList(Person person) throws RemoteException {
persons.add(person);
return persons;
}
};
}
该服务端运行在独立进程, 主要是对AIDL接口中的方法进行了实现。
4.客户端调用
首先进行服务的绑定。并在ServiceConnection的回调方法中获得服务端返回的Binder实例。
Intent intent =
newIntent(MainActivity.this,IRemoteService.class);
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
private ServiceConnection serviceConnection =
newServiceConnection() {
@
Override
public voidonServiceConnected(ComponentName name, IBinder service) {
mGetData =
IGetData.Stub.asInterface(service);
}
@
Override
public voidonServiceDisconnected(ComponentName name) {
}
};
当点击按钮后, 即可远程调用获得的IgetData对象的getPersonList()方法, 将一个初始化好的Person类对象作为参数传入, 将返回的List中的Person实例的内容全部Toast出来, 这里点击了四次, 添加了四个Person以及其年龄信息( 亲爱的东大114岁了, Android6岁, 我永远18岁QAQ) , 效果如下, 这样整个客户端和服务端的自定义对象跨进程传递的过程就使用AIDL完成了。
文章图片
参考源码地址点击下载。请大家多点赞支持~
推荐阅读
- Android实际开发之网络请求组件的封装(OkHttp为核心)
- Android商城开发系列—— 活动广告布局实现
- Android 图片加载框架Universal-Image-Loader源码解析
- cmake编译android平台的libPoco
- Android商城开发系列—— 使用RecyclerView展示首页数据
- 安卓开发中Sqlte的学习心得
- uses-sdk:minSdkVersion 1 cannot be smaller than version 4 declared in library [com.android.support:s
- AppInventor2笔记
- Android启动模式以及IntentFilter匹配规则