AIDL自动生成源码分析以及根据自动生成的源码来自定义类实现IPC
来源:互联网 发布:js 字符串一行打印 编辑:程序博客网 时间:2024/06/07 20:51
前言
今天要写的就是AIDL的具体使用、AIDL自动生成源码分析以及根据自动生成的源码自定义类来实现IPC。这篇博客的着重点就在于源码分析和自定义类,至于使用过程中的细节并没有介绍。开始切入正题!
服务端进程使用
在服务端进程中我们定义AIDL文件,以学生类为例,我们对外接口就是IStudentManager.aidl文件,自定义类AIDL声明文件就是Student.aidl文件,对应我们实体类就是Student,三者代码如下:
Student.java:
package com.lgy.aidl.aidl;import android.os.Parcel;import android.os.Parcelable;public class Student implements Parcelable { private String mNo; private String mName; private String mSex; private String mTel; private Student(Parcel in) { mNo = in.readString(); mName = in.readString(); mSex = in.readString(); mTel = in.readString(); } public static final Creator<Student> CREATOR = new Creator<Student>() { @Override public Student createFromParcel(Parcel in) { return new Student(in); } @Override public Student[] newArray(int size) { return new Student[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeString(mNo); parcel.writeString(mName); parcel.writeString(mSex); parcel.writeString(mTel); } public String getmNo() { return mNo; } public void setmNo(String mNo) { this.mNo = mNo; } public String getmName() { return mName; } public void setmName(String mName) { this.mName = mName; } public String getmSex() { return mSex; } public void setmSex(String mSex) { this.mSex = mSex; } public String getmTel() { return mTel; } public void setmTel(String mTel) { this.mTel = mTel; }}
Student.aidl:
// Student.aidlpackage com.lgy.aidl.aidl;import com.lgy.aidl.aidl.Student;parcelable Student;
IStudentManager.aidl:
// IStudentManager.aidlpackage com.lgy.aidl.aidl;import com.lgy.aidl.aidl.Student;interface IStudentManager { List<Student> getAllStudent(); void addStudent(in Student stu);}
此时我们程序的结构图:
我们在服务端进程中开启Service,在Service中返回给客户端进程IBinder对象,此时的IBinder对象就是我们刚刚IStudentManager.aidl文件生成源码中静态内部类Stub,客户端拿到服务端IBinder对象,就可以进行进程间的通信了。
Service代码:
package com.lgy.aidl;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import com.lgy.aidl.aidl.IStudentManager;import com.lgy.aidl.aidl.Student;import java.util.ArrayList;import java.util.List;public class MyService extends Service { private static final String TAG = "MyService"; private ArrayList<Student> mList = new ArrayList<>(); private IStudentManager.Stub mBinder = new IStudentManager.Stub() { @Override public List<Student> getAllStudent() throws RemoteException { Log.i(TAG,"客户端调用getAllStudent方法执行,学生人数" + mList.size()); return mList; } @Override public void addStudent(Student stu) throws RemoteException { Log.i(TAG,"客户端调用addStudent方法执行之前学生人数" + mList.size()); mList.add(stu); Log.i(TAG, "客户端调用addStudent方法执行之后学生人数" + mList.size()); } }; public MyService() { } @Override public void onCreate() { super.onCreate(); Student stu1 = new Student("1","张三","男","13718447489"); Student stu2 = new Student("2","李四","男","13699485793"); Student stu3 = new Student("3","貂蝉","女","15896345892"); mList.add(stu1); mList.add(stu2); mList.add(stu3); Log.i(TAG,"服务端Service启动!当前总共有" + mList.size() + "名学生"); } @Override public IBinder onBind(Intent intent) { return mBinder; }}
到此服务的进程代码编写完毕!
客户端进程使用
我们将服务端进程中所需要的AIDL文件和相关自定义的实体类,原封不动的移动到客户端进程程序中。我们在客户端进程中只需要绑定Service,获取拿到服务端的IBinder对象即可。
package com.lgy.aidl;import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.ActionBarActivity;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import com.lgy.aidl.aidl.IStudentManager;import com.lgy.aidl.aidl.Student;import java.util.ArrayList;public class MainActivity extends Activity { public static final String TAG = "MainActivity"; private IStudentManager mStudentManager; private ArrayList<Student> mList ; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.i(TAG, "客户端进程连接成功"); mStudentManager = IStudentManager.Stub.asInterface(iBinder); try { mList = (ArrayList<Student>) mStudentManager.getAllStudent(); Log.i(TAG,"客户端进程连接成功之后,返回的学生人数" + mList.size()); } catch (RemoteException e) { e.printStackTrace(); } Student stu4 = new Student("4","Tom","男","15678958962"); Student stu5 = new Student("5","lily","女","18963526354"); try{ mStudentManager.addStudent(stu4); mStudentManager.addStudent(stu5); }catch (RemoteException e){ e.printStackTrace(); } try { mList = (ArrayList<Student>) mStudentManager.getAllStudent(); Log.i(TAG, "添加了2名学生后,返回的学生人数" + mList.size()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(this,MyService.class); bindService(intent,mConnection,BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); }}
好了,到此客户端进程程序就写好,我们运行一下程序看看我们打印的log,和我们预想的是否一致。
AIDL生成代码分析
现在我们分析一下我们写的AIDL文件生成的Java类:
/* * This file is auto-generated. DO NOT MODIFY. * Original file: E:\\sunshine\\lgy\\aidl\\app\\src\\main\\aidl\\com\\lgy\\aidl\\aidl\\IStudentManager.aidl */package com.lgy.aidl.aidl;public interface IStudentManager extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.lgy.aidl.aidl.IStudentManager { private static final java.lang.String DESCRIPTOR = "com.lgy.aidl.aidl.IStudentManager"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.lgy.aidl.aidl.IStudentManager interface, * generating a proxy if needed. */ public static com.lgy.aidl.aidl.IStudentManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.lgy.aidl.aidl.IStudentManager))) { return ((com.lgy.aidl.aidl.IStudentManager) iin); } return new com.lgy.aidl.aidl.IStudentManager.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 { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_getAllStudent: { data.enforceInterface(DESCRIPTOR); java.util.List<com.lgy.aidl.aidl.Student> _result = this.getAllStudent(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addStudent: { data.enforceInterface(DESCRIPTOR); com.lgy.aidl.aidl.Student _arg0; if ((0 != data.readInt())) { _arg0 = com.lgy.aidl.aidl.Student.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addStudent(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.lgy.aidl.aidl.IStudentManager { 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; } @Override public java.util.List<com.lgy.aidl.aidl.Student> getAllStudent() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.lgy.aidl.aidl.Student> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getAllStudent, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.lgy.aidl.aidl.Student.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addStudent(com.lgy.aidl.aidl.Student stu) 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 ((stu != null)) { _data.writeInt(1); stu.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getAllStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } **public java.util.List<com.lgy.aidl.aidl.Student> getAllStudent() throws android.os.RemoteException; public void addStudent(com.lgy.aidl.aidl.Student stu) throws android.os.RemoteException;**}
从上面自动生成的代码来看,IStudentManager.java类,其实就是一个接口interface、实现了IInterface接口,在里面有2个我们定义的方法getAllStudent和addStudent(代码中粗色部分)。在该接口中有一个静态内部类Stub 继承Binder类、实现了IStudentManager接口。
现在我们从哪里讲呢?我们在客户端进程的编写过程中,在绑定Service的时候,创建连接的时候,我们有这么一句:
mStudentManager = IStudentManager.Stub.asInterface(iBinder);
好了,我们看看这个静态内部类Stub的静态内部方法asInterface是如何实现的?
if ((obj == null)) { return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin != null) && (iin instanceof com.lgy.aidl.aidl.IStudentManager))) { return ((com.lgy.aidl.aidl.IStudentManager) iin);}return new com.lgy.aidl.aidl.IStudentManager.Stub.Proxy(obj);
源码中首先判断参数IBinder是否为null, 接着调用Binder对象的queryLocalInterface方法,这个方法又是做什么的呢?
我们继续查看源代码:
/** * Use information supplied to attachInterface() to return the * associated IInterface if it matches the requested * descriptor. */public IInterface queryLocalInterface(String descriptor) { if (mDescriptor.equals(descriptor)) { return mOwner; } return null;}
从源代码中看很简单,判断descriptor字符串和自己内部的字符串相等还是不相等,返回的是一个mOwner对象,那么这个mOwner对象是IInterface接口,如下:
private int mObject;private IInterface mOwner;private String mDescriptor;
我们就要在去看源码中的构造函数Stub()如下:
public Stub() { this.attachInterface(this, DESCRIPTOR); }
继续看attachInterface方法如下:
public void attachInterface(IInterface owner, String descriptor) { mOwner = owner; mDescriptor = descriptor; }
看到这里我想我们应该知道queryLocalInterface的含义了?就是查找当前进程是否和服务端进程在同一个程序进程中,如果在同一个进程的话,那么就直接返回找到自身mOwner IInterface对象 如果不在同一个进程的话,就返回给null。那么最终会返回给我们一个Stub类中的静态代理类Proxy。 也就是说代理类Proxy才是真正的实现IPC的关键!。
好了,我知道了这个代理类Proxy,那么他又是如何实现的呢?
第一:代理类也实现了IStudentManager接口,所以他也会有2个方法去实现。
第二:代理类中的构造和私有函数传递的就是我们IStudentManager.Stub.asInterface(iBinder); IBinder对象。
我们看看两个方法的实现:
@Override public java.util.List<com.lgy.aidl.aidl.Student> getAllStudent() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.lgy.aidl.aidl.Student> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getAllStudent, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.lgy.aidl.aidl.Student.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; }
@Override public void addStudent(com.lgy.aidl.aidl.Student stu) 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 ((stu != null)) { _data.writeInt(1); stu.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } }
在方法的源码实现中我们可以发现就是参数 是否回应,结果的返回都是序列化的Parcel。
在这2个方法中:
mRemote.transact(Stub.TRANSACTION_getAllStudent, _data, _reply, 0);
mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);
这2句才是真正的在多进程间数据通信。
在transact方法中:
/** * Default implementation rewinds the parcels and calls onTransact. On * the remote side, transact calls into the binder to do the IPC. */ public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (false) Log.v("Binder", "Transact: " + code + " to " + this); if (data != null) { data.setDataPosition(0); } boolean r = onTransact(code, data, reply, flags); if (reply != null) { reply.setDataPosition(0); } return r; }
调用onTransact方法此时调用的是服务端的onTransact方法,因Binder对象是服务端的对象:
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_getAllStudent: { data.enforceInterface(DESCRIPTOR); java.util.List<com.lgy.aidl.aidl.Student> _result = this.getAllStudent(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addStudent: { data.enforceInterface(DESCRIPTOR); com.lgy.aidl.aidl.Student _arg0; if ((0 != data.readInt())) { _arg0 = com.lgy.aidl.aidl.Student.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addStudent(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); }
从onTransact源码中我们可以看到参数,是否回应,结果都会作为参数传递过来,然后调用相对应的方法,将结果放回对应的参数中去,客户端进程在获取拿到对应的结果返回。
_reply.readException();_result = _reply.createTypedArrayList(com.lgy.aidl.aidl.Student.CREATOR);
从而整个过程也就完毕!(注意:客户端进程调用mRemote.transact方法和等待服务端onTransact结果 是同步的,也就是说在服务端进程不能做一些耗时的工作,否则客户端进程就会等待 从而可能会造成ANR现象)。
抛开AIDL,自定义代码实现
通过分析,我想我们应该已经有所认识了,那么我们不依靠AIDL文件生成对应的Java类的话,我们其实一样是可以实现IPC的通信。我做个实现步骤总结:
- 定义一个接口类A继承IInterface类,定义我们要实现的方法(按我们的例子就是要写2个方法)。
- 定义一个类B继承Binder类,实现刚刚定义的接口类A
- 定义我们B类的唯一标识DESCRIPTOR,构造函数实现
- 定义我们B类的asInterface静态方法
- 定义我们B类的静态内部类Proxy,实现接口类A
- 在我们定义B类中实现onTransact方法
到此就是需要这6部就完成了自定义类似AIDLJava类文件。剩下的就是我们的使用。在使用的过程中和AIDL完全是一样的,只是这个时候需要用到的IStudentManager、Stub内部类,静态内部类Proxy都是我们自己定义的即可。
看一看我按照以上6部写的类如下:
IStudentManager:
package com.lgy.aidl;import android.os.IInterface;import android.os.RemoteException;import com.lgy.aidl.aidl.Student;import java.util.List;public interface IStudentManager extends IInterface{ public List<Student> getAllStudent() throws RemoteException; public void addStudent(Student stu) throws RemoteException;}
IStudentStub:
package com.lgy.aidl;import android.os.Binder;import android.os.IBinder;import android.os.IInterface;import android.os.Parcel;import android.os.RemoteException;import com.lgy.aidl.aidl.*;import java.util.List;public class IStudentStub extends Binder implements IStudentManager{ public static final String DESCRIPTOR = "com.lgy.aidl.IStudentStub"; public static final int TRANSACTION_getAllStudent = FIRST_CALL_TRANSACTION + 0; public static final int TRANSACTION_addStudent = FIRST_CALL_TRANSACTION + 1; IStudentStub(){ this.attachInterface(this,DESCRIPTOR); } public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_getAllStudent: { data.enforceInterface(DESCRIPTOR); List<Student> _result = this.getAllStudent(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addStudent: { data.enforceInterface(DESCRIPTOR); Student _arg0; if ((0 != data.readInt())) { _arg0 = Student.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addStudent(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } public static IStudentManager asInterface(IBinder binder){ if (null == binder){ return null; } IInterface iin = binder.queryLocalInterface(DESCRIPTOR); if (iin != null && iin instanceof IStudentStub){ return (IStudentManager) iin; } return new Proxy(binder); } @Override public List<Student> getAllStudent() throws RemoteException { return null; } @Override public void addStudent(Student stu) throws RemoteException { } @Override public IBinder asBinder() { return this; } static class Proxy implements IStudentManager{ private IBinder mRemote; Proxy(IBinder binder){ mRemote = binder; } @Override public List<Student> getAllStudent() throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); List<Student> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(TRANSACTION_getAllStudent, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.lgy.aidl.aidl.Student.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addStudent(Student stu) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); if ((stu != null)) { _data.writeInt(1); stu.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(TRANSACTION_addStudent, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public IBinder asBinder() { return mRemote; } }}
我们的使用在客户端和服务器端:
private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.i(TAG, "客户端进程连接成功"); mStudentManager = IStudentStub.asInterface(iBinder); try { mList = (ArrayList<Student>) mStudentManager.getAllStudent(); Log.i(TAG,"客户端进程连接成功之后,返回的学生人数" + mList.size()); } catch (RemoteException e) { e.printStackTrace(); } Student stu4 = new Student("4","Tom","男","15678958962"); Student stu5 = new Student("5","lily","女","18963526354"); try{ mStudentManager.addStudent(stu4); mStudentManager.addStudent(stu5); }catch (RemoteException e){ e.printStackTrace(); } try { mList = (ArrayList<Student>) mStudentManager.getAllStudent(); Log.i(TAG, "添加了2名学生后,返回的学生人数" + mList.size()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { } };
private IStudentStub mBinder = new IStudentStub(){ @Override public List<Student> getAllStudent() throws RemoteException { Log.i(TAG,"客户端调用getAllStudent方法执行,学生人数" + mList.size()); return mList; } @Override public void addStudent(Student stu) throws RemoteException { Log.i(TAG,"客户端调用addStudent方法执行之前学生人数" + mList.size()); mList.add(stu); Log.i(TAG, "客户端调用addStudent方法执行之后学生人数" + mList.size()); } };
我们在看一看运行的log日志是否和我们预期的一致呢?!
再看一下我编写后的程序结构如下:
不知道写到这里大家是否能够理解,有问题大家一起探讨吧!
- AIDL自动生成源码分析以及根据自动生成的源码来自定义类实现IPC
- (根据源码自动生成流程图)AutoFlowchart
- AIDL中根目录自动生成的与aidl文件相对应的java类分析
- 理解AIDL原理以及系统生成的源码
- 根据测试用例的java源码自动生成TestNG的XML文件
- 根据测试用例的java源码自动生成TestNG的XML文件
- android的aidl-手动实现aidl自动生成的Java文件
- 基于TCP网络通信的自动升级程序源码分析--生成升级文件相关的配置文件
- Cacti源码分析:创建图像自动生成title截断问题的排查处理
- AIDL 无法自动生成aidl.java
- myEclipse6.5GA自动生成注册码源码
- Android源码是如何自动生成apk文件的
- 用Enterprise Architect从源码自动生成类图
- 用Enterprise Architect从源码自动生成类图
- 用Enterprise Architect从源码自动生成类图
- 用Enterprise Architect从源码自动生成类图
- Java源码阅读(类图自动生成工具)
- 用Enterprise Architect从源码自动生成类图
- D. Dreamoon and Sets(Codeforces Round #272)
- butterknife 注解成功但运行报空指针错误
- APP增量更新的实现
- (JAVA+TESTNG 三)Eclipse+TestNG搭建接口自动化测试框架
- 常用的正则表达式
- AIDL自动生成源码分析以及根据自动生成的源码来自定义类实现IPC
- Leetcode-length-of-last-word
- Thinking in Java之类内部变量定义先后顺序
- 内存泄露
- Letter Combinations of a Phone Number
- ZZULUI-1183平面点排序(一)(结构体专题)
- 140. Word Break II
- SpringMVC的Handler处理及url映射
- 机器学习中的数学-回归(regression)、梯度下降(gradient descent)<1>