Android开发之---AIDL
在Android开发中,有时会用到多进程通信,这时,可选的方案为:
1. Bundle :四大组件之间的进程间通信
2. 文件共享 :适合无并发情景
3. Messager : 低并发的一对多即使通信,无RPC需求或无须要返回结果的RPC需求
4. AIDL :一对多通信且有RPC需求
5. Content Provider : 一对多的进程间数据共享
6. Socket : 网络数据交换
这里使用AIDL来举例,其实,Message底层也是AIDL来处理的,是对AIDL的一个简单封装,AIDL用到一个Android系统的核心--Binder,Binder在Android系统中用来处理进程间通信,它基于OpenBinder来实现的,是一个类似于COM和CORBA的分布式组件架构,其本身也挺复杂的,源码还没看懂,一开始看时感觉云里雾里的,但是,先用着吧,实践帮助理论,二者不断交错,肯定有一天弄懂的,哈哈~
在一个APP应用里,通过process属性可以方便测试多进程通信,这里采用另一种方式,使用两个APP应用,一个是服务端,一个是客户端,其实,两种方式都一样道理,因为对于同一个应用的不同组件,如果它们运行在不同的进程中,它们与分别属于两个应用没有什么本质区别。
开始测试:
1. 新建服务端项目:TestAIDLServer:

2. 新建一个用户管理类User.java,AIDL需要使用Paracelable来序列化和反序列化对象:
package cn.linjk.testaidlserver; import android.os.Parcel;
import android.os.Parcelable; /**
* Created by LinJK on 06/12/2016.
*/ public class User implements Parcelable{ public int userId;
public String userName; public User(int userId, String userName) {
this.userId = userId;
this.userName = userName;
} @Override
public int describeContents() {
return 0;
} @Override
public void writeToParcel(Parcel pParcel, int pI) {
pParcel.writeInt(userId);
pParcel.writeString(userName);
} public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
@Override
public User createFromParcel(Parcel pParcel) {
return new User(pParcel);
} @Override
public User[] newArray(int pI) {
return new User[pI];
}
}; private User(Parcel in) {
userId = in.readInt();
userName = in.readString();
}
}
3. 新建AIDL文件夹并新建aidl接口文件:
3.1 新建aidl文件夹:

新建完成后目录结构如下:

3.2 新建aidl接口文件,在接口文件用到了User类,也需要新建对应的类的aidl文件来声明类,并且在接口文件需要显示import这个User类

这里声明了两个方式:新增用户和获取当前所有用户的方法。
(小插曲:
我们在这里make一次工程后,会生成一个java文件:

使用aidl来处理,我们就不用自己写Binder通信,当然,也可以手写,这样有利于更加理解binder的原理,但是初学者就麻烦了,所有,两者都可以实现,AIDL文件的本质就是android系统为我们提供了一种快速实现binder的工具而已。
)
4. 为了方便AIDL开发,所有和AIDL相关的类和文件放入同一个包内,如果类的完整路径不一样,在反序列化时会失败,开发用户端时直接把这个包复制到客户端应用即可,这里把User类放进与aidl同级目录下。
5. 服务新建一个Service,实现AIDL接口方法(这里为了方便,先在服务端准备两条数据):
package cn.linjk.testaidlserver; 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.List;
import java.util.concurrent.CopyOnWriteArrayList; import cn.linjk.testaidlserver.aidl.IUserManager;
import cn.linjk.testaidlserver.aidl.User; /**
* Created by LinJK on 06/12/2016.
*/ public class ServiceUserManager extends Service{ private static final String TAG = ServiceUserManager.class.getSimpleName(); private CopyOnWriteArrayList<User> mUserCopyOnWriteArrayList = new CopyOnWriteArrayList<>(); private Binder mBinder = new IUserManager.Stub() {
@Override
public void addUser(User user) throws RemoteException {
mUserCopyOnWriteArrayList.add(user);
} @Override
public List<User> getAllUsers() throws RemoteException {
return mUserCopyOnWriteArrayList;
}
}; @Override
public void onCreate() {
super.onCreate();
mUserCopyOnWriteArrayList.add(new User(1, "Jim"));
mUserCopyOnWriteArrayList.add(new User(2, "Jim_LinJK"));
} @Nullable
@Override
public IBinder onBind(Intent pIntent) {
return mBinder;
}
}
6. 启动服务端,发现出现如下错误,找不到数据类?

修改app/build.gradle文件配置:

7. 可以了,服务端开启完成。
8. 新建客户端项目:

9. 把服务端的src/main/aidl文件下的文件拷贝到客户端同样目录路径下(如果同一个APP的话就不用拷贝了,共用的),完成后如下:

10. 编写连接服务端代码:
因为这里需要连接服务端的servicemanager,所以需要把ServiceUserManager类也移到aidl文件夹下面,并保证服务端项目和客户端项目文件和其内容一致,最后aidl文件夹下文件为:

package cn.linjk.testaidlclient; import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log; import java.util.List; import cn.linjk.testaidlserver.aidl.IUserManager;
import cn.linjk.testaidlserver.aidl.ServiceUserManager;
import cn.linjk.testaidlserver.aidl.User; public class MainActivity extends AppCompatActivity {
private final static String TAG = MainActivity.class.getSimpleName(); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); bindService(new Intent(this, ServiceUserManager.class), mServiceConnection, Context.BIND_AUTO_CREATE);
} @Override
protected void onDestroy() {
unbindService(mServiceConnection);
super.onDestroy();
} private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName pComponentName, IBinder pIBinder) {
IUserManager lvIUserManager = IUserManager.Stub.asInterface(pIBinder); try {
List<User> lvUserList = lvIUserManager.getAllUsers();
for (User lvUser : lvUserList) {
Log.i(TAG, "[User name] : " + lvUser.userName + " and [User id] : " + lvUser.userId);
}
}
catch (Exception e) {
e.printStackTrace();
}
} @Override
public void onServiceDisconnected(ComponentName pComponentName) {
//
}
};
}
11. 先启动服务端APP
12. 再启动客户端APP,可以看到,客户端APP能获取服务端APP的数据:

13. 在客户端APP增加一个按钮,用于向服务端新增一条用户数据,界面代码比较简单,就不写了,看看按钮的监听部分代码:
btnAddUser.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View pView) {
try {
User lvUser = new User(3, "Apple");
lvIUserManager.addUser(lvUser);
//
List<User> lvUserList = lvIUserManager.getAllUsers();
for (User lvUserTmp : lvUserList) {
Log.i(TAG, "[User name] : " + lvUserTmp.userName + " and [User id] : " + lvUserTmp.userId);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
});
14. 再次运行客户端APP,看看日志:
一开始没有id为3的用户,点击按钮后,再次看看用户list,新增了一个用户成功: 
到这里,aidl的测试已经可以了,当然,整个逻辑还有很多异常没考虑,这里就不全部完善了,例如不用每次从服务器查询数据,而是服务器数据更新了自动提醒客户端进行界面刷新功能等。
代码已提交GitHub: https://github.com/linjk/TestAIDL.git
Android开发之---AIDL的更多相关文章
- Android开发了解——AIDL
AIDL:Android Interface Definition Language,即Android接口定义语言. 什么是AIDL Android系统中的进程之间不能共享内存,因此,需要提供一些机制 ...
- Android开发-解决 AIDL 中找不到couldn't find import for class错误
最近在使用AIDL做IPC的时候,在处理复杂的数据类型的时候,编译器总是报couldn't find import for class错误,所以在这里总结下AIDL使用的时候的一些注意事项,希望对你能 ...
- Android开发-API指南-AIDL
Android Interface Definition Language (AIDL) 英文原文:http://developer.android.com/guide/components/aidl ...
- Android开发,Eclipse创建aidl接口时,出错
Android开发中,当我们需要调用远程Service时,我们一般通过远程接口(RMI)来实现的,而Android的RMI需要AIDL(Android Interface Definition Lan ...
- android开发系列之aidl
aidl在android开发中的主要作用就是跨进程通讯来着,说到进程相比很多人都是非常熟悉了,但是为什么会有跨进程通讯这个概念呢?原来在android系统中,有这么一套安全机制,为了各个Apk数据的独 ...
- Android开发——进程间通信之AIDL(二)
0. 前言 不论是Android还是其它操作系统.都会有自己的IPC机制.所谓IPC(Inter-Process Communication)即进程间通信.首先线程和进程是非常不同的概念,线程是CP ...
- Qt for Android开发环境搭建及测试过程记录
最近学习了Qt的QML编程技术,感觉相较于以前的QtGUI来说更方便一些,使用QML可以将界面与业务逻辑解耦,便于开发. QML支持跨平台,包括支持Android平台,因此可以使用Qt的QML进行An ...
- Android开发学习清单
目录: 第1章 Android应用与开发环境1.1 Android的发展和历史1.1.1 Android的发展和简介1.1.2 Android平台架构及特性1.2 搭建Android开发环境1.2.1 ...
- Android开发权威指南(第2版)新书发布
<Android 开发权威指南(第二版)>是畅销书<Android开发权威指南>的升级版,内容更新超过80%,是一本全面介绍Android应用开发的专著,拥有45 章精彩内容供 ...
随机推荐
- jprofiler_监控远程linux服务器的JVM进程(实践)
几天前写了一篇文章,jprofiler_监控远程linux服务器的tomcat进程(实践),介绍了使用jprofiler怎样监控远程linux的tomcat进程,这两天想了想,除了可以监控tomcat ...
- 怎么样修改小猪cms(从功能库添加)模块关键字
需求:修改或者添加从功能库添加中的关键字 这里以添加咨询投诉为列: 找到wwwroot\PigCms\Lib\Action\User目录下的LinkAction.class.php文件(手动找不到直接 ...
- shiro登陆后没有返回设置的successUrl?
第一次学习shiro的时候,并没有发现很大的问题.但后来在做项目的时候,特别是当访问的url是iframe的页面的时候,session又过期了,跳转到登陆页,完成登陆操作后,返回了只有iframe的页 ...
- socket编程基础
socket编程 什么是socket 定义 socket通常也称作套接字,用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过套接字向网络发出请求或者应答网络请求. socket起源于Unix ...
- 探索 OpenStack 之(8):Neutron 深入探索之 OVS + GRE 之 完整网络流程 篇
前两篇博文分别研究了Compute节点和Neutron节点内部的网络架构.本文通过一些典型流程案例来分析具体网络流程过程. 0. 环境 同 学习OpenStack之(7):Neutron 深入学习之 ...
- 数据存储_ SQLite(3)
SQLite的应用 一.简单说明 1.在iOS中使用SQLite3,首先要添加库文件 libsqlite3.dylib 2.导入主头文件 #import <sqlite3.h> 二.具体说 ...
- MRDS学习二——机械车
准备机械车: 第一步:从Service中选择一个Generic Differential Drive (通用差速驱动:同一轴的左右轮胎可以转动不同速度的车子)放入Diagram中. 第二步:对其进行配 ...
- tyvj1089 smrtfun
背景 广东汕头聿怀初中 Train#2 Problem3 描述 现有N个物品,第i个物品有两个属性A_i和B_i.在其中选取若干个物品,使得sum{A_i + B_i}最大,同时sum{A_i},s ...
- mysql数据库 中文乱码
看到一篇很好的文章,转录于此 中文乱码似乎是程序编写中永恒的一个话题和难点,就比如MySQL存取中文乱码,但我想做任何事情,都要有个思路才行,有了思路才知道如何去解决问题,否则,即使一时解决了问题,但 ...
- 【荐】使用eval()、new Function()将JSON字符串转换为JSON对象
在JS中将JSON的字符串解析成JSON数据格式,一般有两种方式: 1.一种为使用eval()函数. 2. 使用Function对象来进行返回解析. 第一种解析方式:使用eval函数来解析,并且使用j ...