阅读本篇文章前, 请先查看一下笔者之前的写的两篇博客文章: Android Service知识 和 Android AIDL使用
进程间通信涉及到客户端和服务端, 肯定有绑定服务的过程, 所以要阅读一下Android Service相关的知识, 跨进程通信的媒介aidl文件,我们也必须要了解怎么创建的,有什么规则,所以请先阅读一下Android AIDL使用这篇文章.
一. 概述
本文重点讲解一下AIDL文件结构以及类中每个方法的含义. 然后把AIDL中每个方法的用途理解清楚后, 我们就不依赖AS自带的工具创建, 而是自己手动去写一个AIDL文件, 在手写的代码中添加自己的日志, 根据打印理清楚客户端与服务端跨进程通信的流程图, 目的加深对IPC机制的理解.
二. AIDL文件结构
这是我创建的一个 IStudentService.aidl 里面有三个方法,然后build一下,系统自动为我们生成一个IStudentService.java类. 先大致看一下类结构和方法:
public interface IStudentService extends android.os.IInterface {
/**
* Default implementation for IStudentService.
*/
public static class Default implements com.example.mysevicejava.IStudentService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*///定向tag
@Override
public java.lang.String getString() throws android.os.RemoteException {
return null;
}
@Override
public void addStudent(com.example.mysevicejava.Student student) throws android.os.RemoteException {
}
//void test(in PathParceTest obb);
@Override
public java.util.List<com.example.mysevicejava.Student> getStudentList() throws android.os.RemoteException {
return null;
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/**
* Local-side IPC implementation stub class.
* 1. Stub是一个抽象类 最终的实现是在service中.
* 2. 同时继承拓展了android.os.Binder.
* 3. Stub 是 IStudentService接口的具体实现类.
*/
public static abstract class Stub extends android.os.Binder implements com.example.mysevicejava.IStudentService {
private static final java.lang.String DESCRIPTOR = "com.example.mysevicejava.IStudentService";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.mysevicejava.IStudentService interface,
* generating a proxy if needed.
这个是方法是在静态抽象类 Stub中, 作用: 用于服务端的Binder对象转换成客户端所需的AIDL接口类型的对象, 此转换过程是区分进程的,如果Client 和 Service端在统一进程中, 那么此方法返回的就是服务端的Stub对象本身, 如果是跨进程的话, 则返回的是Stub.proxy对象.
*/
public static com.example.mysevicejava.IStudentService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.mysevicejava.IStudentService))) {
return ((com.example.mysevicejava.IStudentService) iin);
}
return new com.example.mysevicejava.IStudentService.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getString: {
data.enforceInterface(descriptor);
java.lang.String _result = this.getString();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_addStudent: {
data.enforceInterface(descriptor);
com.example.mysevicejava.Student _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.mysevicejava.Student.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addStudent(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getStudentList: {
data.enforceInterface(descriptor);
java.util.List<com.example.mysevicejava.Student> _result = this.getStudentList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.example.mysevicejava.IStudentService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*///定向tag
@Override
public java.lang.String getString() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getString, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getString();
}
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addStudent(com.example.mysevicejava.Student student) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((student != null)) {
_data.writeInt(1);
student.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addStudent(student);
return;
}
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
//void test(in PathParceTest obb);
@Override
public java.util.List<com.example.mysevicejava.Student> getStudentList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.mysevicejava.Student> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getStudentList, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getStudentList();
}
_reply.readException();
_result = _reply.createTypedArrayList(com.example.mysevicejava.Student.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.example.mysevicejava.IStudentService sDefaultImpl;
}
static final int TRANSACTION_getString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_getStudentList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
public static boolean setDefaultImpl(com.example.mysevicejava.IStudentService impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.example.mysevicejava.IStudentService getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*///定向tag
public java.lang.String getString() throws android.os.RemoteException;
public void addStudent(com.example.mysevicejava.Student student) throws android.os.RemoteException;
//void test(in PathParceTest obb);
public java.util.List<com.example.mysevicejava.Student> getStudentList() throws android.os.RemoteException;
}
根据类结构图, 其实我们只需要搞明白这2个核心实现方法
1. 静态抽象类 Stub;
2. Stub的静态内部类Proxy ;
Question: 写到这里,提个问题,就是google工程师为什么要把 Stub类设计为抽象类啊?
Answer: Stub类extends android.os.Binder 并且 implement 你自定义的AIDL文件中的方法, 它的最终实现是在你的service代码中, 人家google工程师他们只能帮你把模板搭建好, 具体的业务逻辑肯定是自己去实现了.
在服务端中继承IStudentService.Stub这个抽象类, 并在 onBind回调方法中返回IBinder对象
class MyBinder extends IStudentService.Stub{
@Override
public String getString() throws RemoteException {
return "我是从服务端返回的数据: 111";
}
@Override
public void addStudent(Student student) throws RemoteException {
mStudentList.add(student);
}
@Override
public List<Student> getStudentList() throws RemoteException {
return mStudentList;
}
}
@Override
public IBinder onBind(Intent intent) {
Log.e("test", "==服务端==onBind========");
// TODO: Return the communication channel to the service.
return new MyBinder();
}
这个IBinder对象对应的就是客户端中 IBinder service对象.
public void onServiceConnected(ComponentName componentName, IBinder service)
我们逐个来解析:
public interface IStudentService extends android.os.IInterface
2.1 首先IStudentService.java类继承与 IInterface这个接口
package android.os;
/**
* Base class for Binder interfaces. When defining a new interface,
* you must derive it from IInterface.
Binder接口的基类。当定义新接口时,你必须继承它。
*/
public interface IInterface
{
/**
* Retrieve the Binder object associated with this interface.
* You must use this instead of a plain cast, so that proxy objects
* can return the correct result.
检索与此接口关联的Binder对象。
必须使用此方法转换,这样代理对象才能返回正确的结果
*/
public IBinder asBinder();
}
同时它自己也是一个接口, 所有可以在Binder中传输的接口都需要继承IInterface接口, 那么如果要自定义手写AIDL的话, 我们当然必须继承IInterface接口, 好到这里提炼第一条规则出来.
2.2 Binder的唯一标识, 一般用当前Binder的类名表示.
为了一个Binder和一个特定服务接口绑定,以对外提供功能,需要给Binder定义一个DESCRIPTOR
描述,表示我这个Binder是提供特定功能链接的,不是随便可以用的。
通常,DESCRIPTOR
描述会直接使用包名 + 服务接口
。
private static final java.lang.String DESCRIPTOR = "com.example.mysevicejava.IStudentService";
2.3 asInterface(android.os.IBinder obj)
这个是方法是在静态抽象类 Stub中, 作用: 用于服务端的Binder对象转换成客户端所需的AIDL接口类型的对象, 此转换过程是区分进程的,如果Client 和 Service端在统一进程中, 那么此方法返回的就是服务端的Stub对象本身, 如果是跨进程的话, 则返回的是Stub.proxy对象.
public static com.example.mysevicejava.IStudentService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
// queryLocalInterface是Binder的方法,搜索本地是否有可用的对象
// DESCRIPTOR = "com.example.mysevicejava.IStudentService";
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
//如果有,则强制类型转换并返回
if (((iin != null) && (iin instanceof com.example.mysevicejava.IStudentService))) {
return ((com.example.mysevicejava.IStudentService) iin);
}
// //如果没有,则构造一个IStudentService.Stub.Proxy对象
return new com.example.mysevicejava.IStudentService.Stub.Proxy(obj);
}
2.4 Stub的静态内部类Proxy
通过上面的new com.example.mysevicejava.IStudentService.Stub.Proxy(obj)调用过来的
private static class Proxy implements com.example.mysevicejava.IStudentService{
private android.os.IBinder mRemote;
//构造方法
Proxy(android.os.IBinder remote){
mRemote = remote;
}
@Override public android.os.IBinder asBinder(){
return mRemote;
}
public java.lang.String getInterfaceDescriptor(){
return DESCRIPTOR;
}
.......
.......
}
通过代码,我们知道
1. Proxy 实现了 com.example.mysevicejava.IStudentService 里面的3个方法
2. Proxy的asBinder()方法返回的mRemote, mRemote是在Proxy(android.os.IBinder remote) 这个构造方法中赋值的.
3. 网上有另外的一种结论:
asInterface方法的主要作用:如果是多进程操作,参数obj是BinderProxy对象,就new一个proxy接口;通过调用new com.example.mysevicejava.IStudentService.Stub.Proxy(obj) 就可以知道
把BinderProxy对象保存到mRemote变量,mRemote在aidl中是一个辅助变量.
mRemote 就是 BinderProxy对象.
----- 这条结论再后面的文章中验证.先记住就可以了,
三. Stub 和 Proxy 理解
首先从字面上来理解一下: proxy是代理 Stub是存根
AIDL: Android interface Definition Language
如果你觉的AIDL中的proxy / stub 比较难理解的话,先触类旁通一下, 换个思维理解
MIDL:微软接口定义语言Microsoft interface Definition Language, 它是定义COM接口的说明性语言。 关于COM (Component Object Model),中文译为,组件对象模型, 它也是一种进程间通信接口, 具体用法参考: 理解Com(Component Object model) 这篇文章,但不是我们关注的重点, 我们只是借助于它来理解我们的AIDL中的 proxy-stub 模式 , 拿COM的通信模式图看一下:
打个比方,你到自动取款机上去取款
你不会在乎钱具体放在那里,你只想看到足够或更多的钱从出口出来(这就是com的透明性)。你同银行之间的操作完全是取款机代理实现。你的取款请求通过取款机,传到另一头,银行的服务器,他也没有必要知道你在哪儿取钱,他所关心的是你的身份,和你取款多少。当他确认你的权限,就进行相应的操作,返回操作结果给取款机,取款机根据服务器返回结果,从保险柜里取出相应数量的钱给你。你取出卡后,操作完成。取款机不是直接同服务器连接的,他们之间还有一个“存根”,取款机与存根通信,存根又与服务器通信。从某种意义上说存根就是服务器的代理。(参考COM代理与存根)
概念理解:
客户端: 自己
proxy : 取款机 ,可以理解为银行金融系统取款业务的代理
服务端: 银行金融系统
Stub: 取款凭证(显示交易时间,交易金额,存钱/取钱), 它作为银行金融系统的实体存根
再回到AIDLFramework层的架构,如下图:
换而言之,Android就是在传统的C/S架构中加入了一层,实现IPC。图中表明,AIDL类似COM的Proxy/Stub架构。不过是现在android自己的序列化类Pacel。
客户端的代码中调用
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e("test", " componentName :" + componentName);
mIStudentService = IStudentService.Stub.asInterface(iBinder);
}
我们再回到2.3 asInterface(android.os.IBinder obj) 这个方法中来
从字面意思看,Stub是存根,Proxy是代理,而这个Stub是谁的存根呢?Proxy又是谁的代理呢?
我理解的是 :
Stub是 服务端Binder实体的存根.
Proxy则是Stub的代理.
Stub类: 服务实体,Binder的实现类,服务端一般会实例化一个Binder对象,在服务端onBind中绑定, 客户端asInterface获取到Stub。 这个类在编译aidl文件后自动生成,它继承自Binder,表示它是一个Binder本地对象; 它是一个抽象类,实现了IInterface接口,表明它的子类需要实现Server将要提供的具体能力(即aidl文件中声明的方 法)
四. 手写AIDL
我们先来看一下代码目录结构:
分为4个部分:客户端, 服务端 , 手写AIDL文件, javabean类
直接上代码:
1. 客户端ClientActivity.java
/**
* @ProjectName: WriteAIDLTest
* @PackageName: com.example.writeaidltest
* @Description: java类作用描述
* @Author: 作者名
* @CreateDate: 23-3-13 下午1:55
* @Version: 1.0
*/
public class ClientActivity extends Activity {
private Intent intent;
private IStudent mIStudent;
//是否绑定成功
boolean mBound = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, MyServer.class);
Button btn = (Button)findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mBound) {
try {
Log.e("test", "mIStudent.getString() 当前线程 :" + Thread.currentThread().getName());
String text = mIStudent.getString();
Log.e("test", "mIStudent.getString() after ");
Toast.makeText(ClientActivity.this, "内容: " + text, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
Button btn1 = (Button)findViewById(R.id.button1);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mBound) {
try {
mIStudent.addStudent(new Student(3, "王五"));
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
Button btn2 = (Button)findViewById(R.id.button2);
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mBound) {
try {
Log.e("test", "获取服务端所有学生的信息: "+mIStudent.getStudentList());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
Log.e("test", "===客户端===onServiceConnected=====service是一个什么对象: ="+service.getClass().getCanonicalName());
mBound = true;
mIStudent = Stub.asInterface(service);
Log.e("test", "===客户端 mIStudent是一个什么对象:" + mIStudent.getClass().getCanonicalName());
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e("test", "====onServiceDisconnected=====");
mBound = false;
}
};
//在onstart方法中 调用 bindservice 绑定服务
@Override
protected void onStart() {
super.onStart();
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
//在onstop方法中, 调用unbindservice 解绑服务
@Override
protected void onStop() {
super.onStop();
unbindService(connection);
mBound = false;
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
2. 服务端代码MyServer.java
/**
* @ProjectName: WriteAIDLTest
* @PackageName: com.example.writeaidltest.service
* @Description: java类作用描述
* @Author: 作者名
* @CreateDate: 23-3-13 下午3:12
* @Version: 1.0
*/
public class MyServer extends Service {
private List<Student> mStudentList = new ArrayList<>();
@Override
public void onCreate() {
super.onCreate();
mStudentList.add(new Student(1, "张三"));
mStudentList.add(new Student(2, "李四"));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e("test", "==服务端==onBind===new MyBinder()是一个什么对象====="+new MyBinder().getClass().getCanonicalName());
//return new MyBinder();
Log.e("test", "==服务端==onBind==myBinder是一个什么对象====="+myBinder.toString());
return myBinder;
}
IBinder myBinder = new Stub() {
@Override
public String getString() throws RemoteException {
return "服务端数据 777";
}
@Override
public void addStudent(Student student) throws RemoteException {
mStudentList.add(student);
}
@Override
public List<Student> getStudentList() throws RemoteException {
return mStudentList;
}
};
class MyBinder extends Stub{
@Override
public String getString() throws RemoteException {
return "服务端数据 111";
}
@Override
public void addStudent(Student student) throws RemoteException {
mStudentList.add(student);
}
@Override
public List<Student> getStudentList() throws RemoteException {
return mStudentList;
}
}
@Override
public void onDestroy() {
Log.e("test", "==服务端=onDestroy=====");
super.onDestroy();
}
}
3. 序列化 Student.java
public class Student implements Parcelable {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
public void readFromParcel(Parcel parcel) {
this.id = parcel.readInt();
this.name = parcel.readString();
}
public static Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
@Override
public Student createFromParcel(Parcel source) {
return new Student(source);
}
@Override
public Student[] newArray(int size) {
return new Student[0];
}
};
private Student(Parcel in) {
this.id = in.readInt();
this.name = in.readString();
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
4. 最重要,手动仿写AIDL文件 IStudent.java
相当于 IStudent.aidl 文件用安卓自带工具生成 IStudent.java
/**
* @ProjectName: WriteAIDLTest
* @PackageName: com.example.writeaidltest.aidlfile
* @Description: 手动仿写AIDL文件
* @Author: 作者名
* @CreateDate: 23-3-13 下午1:58
* @Version: 1.0
*/
public interface IStudent extends android.os.IInterface {
//定义一个DESCRIPTOR
//意图: 为了一个Binder和一个特定服务接口绑定,以对外提供功能,需要给Binder定义一个DESCRIPTOR描述,表示我这个Binder是提供特定功能链接的,不是随便可以用的
public static final java.lang.String DESCRIPTOR = "com.example.writeaidltest.aidlfile.IStudentService";
//定义操作数据的方法
//1. 从服务端获取一个简单的字符串
String getString() throws RemoteException;
//2. 客户端往服务端 添加student对象
void addStudent(Student student) throws RemoteException;
//3. 客户端从服务段获取 所有Student的信息
List<Student> getStudentList() throws RemoteException;
//定义方法的id号
static final int TRANSACTION_getString = IBinder.FIRST_CALL_TRANSACTION + 0;
static final int TRANSACTION_addStudent = IBinder.FIRST_CALL_TRANSACTION + 1;
static final int TRANSACTION_getStudentList = IBinder.FIRST_CALL_TRANSACTION + 2;
}
手动仿写AIDL文件 Stub.java
抽象类 Stub
public abstract class Stub extends android.os.Binder implements IStudent{
//构造方法
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static IStudent asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (iin != null && (iin instanceof IStudent)) {
return (IStudent)iin;
}
// 传入binder对象,返回一个服务代理对象
return new Proxy(obj);
}
@SuppressLint("NewApi")
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION:
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_getString:
// 获取IBinder接口标志
data.enforceInterface(DESCRIPTOR);
//这个是服务端自己实现getString方法,获取返回值
String stringResult = this.getString();
Log.e("test", " stub onTransact 当前线程: "+Thread.currentThread().getName());
reply.writeNoException();
reply.writeString(stringResult);
return true;
case TRANSACTION_addStudent:
// 获取IBinder接口标志
data.enforceInterface(DESCRIPTOR);
// 获取传入的Student对象
Student arg0 = null;
if (data.readInt() != 0) {
arg0 = Student.CREATOR.createFromParcel(data);
}
this.addStudent(arg0);
reply.writeNoException();
return true;
case TRANSACTION_getStudentList:
data.enforceInterface(DESCRIPTOR);
//
List<Student> studentList = null;
studentList = this.getStudentList();
reply.writeNoException();
reply.writeTypedList(studentList);
return true;
}
return super.onTransact(code, data, reply, flags);
}
@Override
public IBinder asBinder() {
return this;
}
}
手动仿写 Proxy.java
public class Proxy implements IStudent{
private IBinder mRemote;
public Proxy(IBinder remote) {
mRemote = remote;
Log.e("test", "===Proxy中 mRemote 是一个什么对象: " + mRemote.getClass().getCanonicalName());
}
@Override
public String getString() throws RemoteException {
Parcel data = Parcel.obtain(); // 跨进程传输数据对象
Parcel reply = Parcel.obtain(); // 跨进程传输返回结果
java.lang.String _result;
try {
data.writeInterfaceToken(DESCRIPTOR);
// 调Stub的onTransact方法进行Stub.TRANSACTION_getString,远端返回
Log.e("test", "mRemote transact 当前线程 :" + Thread.currentThread().getName());
mRemote.transact(TRANSACTION_getString, data, reply, 0);
reply.readException();
_result = reply.readString();
}finally {
data.recycle();
reply.recycle();
}
return _result;
}
@Override
public void addStudent(Student student) throws RemoteException {
Parcel data = Parcel.obtain(); // 跨进程传输数据对象
Parcel reply = Parcel.obtain(); // 跨进程传输返回结果
try{
// 写入IBinder接口标志,一般为全类名,用户数据校验
data.writeInterfaceToken(DESCRIPTOR);
if (student != null){
//写入数据
data.writeInt(1);
student.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
// 调Stub的onTransact方法进行Stub.TRANSACTION_addBook处理,远端返回
mRemote.transact(Stub.TRANSACTION_addStudent, data, reply, 0);
reply.readException();
} finally {
data.recycle();
reply.recycle();
}
}
@Override
public List<Student> getStudentList() throws RemoteException {
Parcel data = Parcel.obtain(); // 跨进程传输数据对象
Parcel reply = Parcel.obtain(); // 跨进程传输返回结果
List<Student> result;
try {
// 写入IBinder接口标志,一般为全类名,用户数据校验
data.writeInterfaceToken(DESCRIPTOR);
// 调Stub的onTransact方法进行Stub.TRANSACTION_getStudentList,远端返回
mRemote.transact(TRANSACTION_getStudentList, data, reply, 0);
reply.readException();
result = reply.createTypedArrayList(Student.CREATOR);
} finally {
reply.recycle();
data.recycle();
}
return result;
}
// 返回Stub类传入的Binder对象
@Override
public IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
}
清单AndroidManifest.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.writeaidltest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.WriteAIDLTest">
<activity android:name=".client.ClientActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- service 运行在另外一个进程中 -->
<service
android:name=".service.MyServer"
android:exported="true"
android:enabled="true"
android:process=":remote">
<intent-filter>
<action android:name="com.my.binder" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
</application>
上面的例子是模拟进程间通信的整个过程,可以通过log看出客户端发送数据给服务端,然后服务端处理之后再返回给客户端的整个流程。
大家可以通过这个Demo去学习AIDL的原理,供参考!
Demo 已上传: https://download.csdn.net/download/u012514113/87906468