当前位置:   article > 正文

Android 进程间通信机制(六) 手写AIDL文件

手写aidl

  阅读本篇文章前, 请先查看一下笔者之前的写的两篇博客文章: Android Service知识  和  Android AIDL使用

        进程间通信涉及到客户端和服务端, 肯定有绑定服务的过程, 所以要阅读一下Android Service相关的知识,   跨进程通信的媒介aidl文件,我们也必须要了解怎么创建的,有什么规则,所以请先阅读一下Android AIDL使用这篇文章.

一. 概述

      

       本文重点讲解一下AIDL文件结构以及类中每个方法的含义.  然后把AIDL中每个方法的用途理解清楚后, 我们就不依赖AS自带的工具创建, 而是自己手动去写一个AIDL文件, 在手写的代码中添加自己的日志, 根据打印理清楚客户端与服务端跨进程通信的流程图, 目的加深对IPC机制的理解.

二. AIDL文件结构

 这是我创建的一个 IStudentService.aidl   里面有三个方法,然后build一下,系统自动为我们生成一个IStudentService.java类. 先大致看一下类结构和方法:

  1. public interface IStudentService extends android.os.IInterface {
  2. /**
  3. * Default implementation for IStudentService.
  4. */
  5. public static class Default implements com.example.mysevicejava.IStudentService {
  6. /**
  7. * Demonstrates some basic types that you can use as parameters
  8. * and return values in AIDL.
  9. *///定向tag
  10. @Override
  11. public java.lang.String getString() throws android.os.RemoteException {
  12. return null;
  13. }
  14. @Override
  15. public void addStudent(com.example.mysevicejava.Student student) throws android.os.RemoteException {
  16. }
  17. //void test(in PathParceTest obb);
  18. @Override
  19. public java.util.List<com.example.mysevicejava.Student> getStudentList() throws android.os.RemoteException {
  20. return null;
  21. }
  22. @Override
  23. public android.os.IBinder asBinder() {
  24. return null;
  25. }
  26. }
  27. /**
  28. * Local-side IPC implementation stub class.
  29. * 1. Stub是一个抽象类 最终的实现是在service中.
  30. * 2. 同时继承拓展了android.os.Binder.
  31. * 3. Stub 是 IStudentService接口的具体实现类.
  32. */
  33. public static abstract class Stub extends android.os.Binder implements com.example.mysevicejava.IStudentService {
  34. private static final java.lang.String DESCRIPTOR = "com.example.mysevicejava.IStudentService";
  35. /**
  36. * Construct the stub at attach it to the interface.
  37. */
  38. public Stub() {
  39. this.attachInterface(this, DESCRIPTOR);
  40. }
  41. /**
  42. * Cast an IBinder object into an com.example.mysevicejava.IStudentService interface,
  43. * generating a proxy if needed.
  44. 这个是方法是在静态抽象类 Stub中,  作用: 用于服务端的Binder对象转换成客户端所需的AIDL接口类型的对象, 此转换过程是区分进程的,如果Client 和 Service端在统一进程中, 那么此方法返回的就是服务端的Stub对象本身, 如果是跨进程的话, 则返回的是Stub.proxy对象.
  45. */
  46. public static com.example.mysevicejava.IStudentService asInterface(android.os.IBinder obj) {
  47. if ((obj == null)) {
  48. return null;
  49. }
  50. android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  51. if (((iin != null) && (iin instanceof com.example.mysevicejava.IStudentService))) {
  52. return ((com.example.mysevicejava.IStudentService) iin);
  53. }
  54. return new com.example.mysevicejava.IStudentService.Stub.Proxy(obj);
  55. }
  56. @Override
  57. public android.os.IBinder asBinder() {
  58. return this;
  59. }
  60. @Override
  61. public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
  62. java.lang.String descriptor = DESCRIPTOR;
  63. switch (code) {
  64. case INTERFACE_TRANSACTION: {
  65. reply.writeString(descriptor);
  66. return true;
  67. }
  68. case TRANSACTION_getString: {
  69. data.enforceInterface(descriptor);
  70. java.lang.String _result = this.getString();
  71. reply.writeNoException();
  72. reply.writeString(_result);
  73. return true;
  74. }
  75. case TRANSACTION_addStudent: {
  76. data.enforceInterface(descriptor);
  77. com.example.mysevicejava.Student _arg0;
  78. if ((0 != data.readInt())) {
  79. _arg0 = com.example.mysevicejava.Student.CREATOR.createFromParcel(data);
  80. } else {
  81. _arg0 = null;
  82. }
  83. this.addStudent(_arg0);
  84. reply.writeNoException();
  85. return true;
  86. }
  87. case TRANSACTION_getStudentList: {
  88. data.enforceInterface(descriptor);
  89. java.util.List<com.example.mysevicejava.Student> _result = this.getStudentList();
  90. reply.writeNoException();
  91. reply.writeTypedList(_result);
  92. return true;
  93. }
  94. default: {
  95. return super.onTransact(code, data, reply, flags);
  96. }
  97. }
  98. }
  99. private static class Proxy implements com.example.mysevicejava.IStudentService {
  100. private android.os.IBinder mRemote;
  101. Proxy(android.os.IBinder remote) {
  102. mRemote = remote;
  103. }
  104. @Override
  105. public android.os.IBinder asBinder() {
  106. return mRemote;
  107. }
  108. public java.lang.String getInterfaceDescriptor() {
  109. return DESCRIPTOR;
  110. }
  111. /**
  112. * Demonstrates some basic types that you can use as parameters
  113. * and return values in AIDL.
  114. *///定向tag
  115. @Override
  116. public java.lang.String getString() throws android.os.RemoteException {
  117. android.os.Parcel _data = android.os.Parcel.obtain();
  118. android.os.Parcel _reply = android.os.Parcel.obtain();
  119. java.lang.String _result;
  120. try {
  121. _data.writeInterfaceToken(DESCRIPTOR);
  122. boolean _status = mRemote.transact(Stub.TRANSACTION_getString, _data, _reply, 0);
  123. if (!_status && getDefaultImpl() != null) {
  124. return getDefaultImpl().getString();
  125. }
  126. _reply.readException();
  127. _result = _reply.readString();
  128. } finally {
  129. _reply.recycle();
  130. _data.recycle();
  131. }
  132. return _result;
  133. }
  134. @Override
  135. public void addStudent(com.example.mysevicejava.Student student) throws android.os.RemoteException {
  136. android.os.Parcel _data = android.os.Parcel.obtain();
  137. android.os.Parcel _reply = android.os.Parcel.obtain();
  138. try {
  139. _data.writeInterfaceToken(DESCRIPTOR);
  140. if ((student != null)) {
  141. _data.writeInt(1);
  142. student.writeToParcel(_data, 0);
  143. } else {
  144. _data.writeInt(0);
  145. }
  146. boolean _status = mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);
  147. if (!_status && getDefaultImpl() != null) {
  148. getDefaultImpl().addStudent(student);
  149. return;
  150. }
  151. _reply.readException();
  152. } finally {
  153. _reply.recycle();
  154. _data.recycle();
  155. }
  156. }
  157. //void test(in PathParceTest obb);
  158. @Override
  159. public java.util.List<com.example.mysevicejava.Student> getStudentList() throws android.os.RemoteException {
  160. android.os.Parcel _data = android.os.Parcel.obtain();
  161. android.os.Parcel _reply = android.os.Parcel.obtain();
  162. java.util.List<com.example.mysevicejava.Student> _result;
  163. try {
  164. _data.writeInterfaceToken(DESCRIPTOR);
  165. boolean _status = mRemote.transact(Stub.TRANSACTION_getStudentList, _data, _reply, 0);
  166. if (!_status && getDefaultImpl() != null) {
  167. return getDefaultImpl().getStudentList();
  168. }
  169. _reply.readException();
  170. _result = _reply.createTypedArrayList(com.example.mysevicejava.Student.CREATOR);
  171. } finally {
  172. _reply.recycle();
  173. _data.recycle();
  174. }
  175. return _result;
  176. }
  177. public static com.example.mysevicejava.IStudentService sDefaultImpl;
  178. }
  179. static final int TRANSACTION_getString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
  180. static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
  181. static final int TRANSACTION_getStudentList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
  182. public static boolean setDefaultImpl(com.example.mysevicejava.IStudentService impl) {
  183. if (Stub.Proxy.sDefaultImpl == null && impl != null) {
  184. Stub.Proxy.sDefaultImpl = impl;
  185. return true;
  186. }
  187. return false;
  188. }
  189. public static com.example.mysevicejava.IStudentService getDefaultImpl() {
  190. return Stub.Proxy.sDefaultImpl;
  191. }
  192. }
  193. /**
  194. * Demonstrates some basic types that you can use as parameters
  195. * and return values in AIDL.
  196. *///定向tag
  197. public java.lang.String getString() throws android.os.RemoteException;
  198. public void addStudent(com.example.mysevicejava.Student student) throws android.os.RemoteException;
  199. //void test(in PathParceTest obb);
  200. public java.util.List<com.example.mysevicejava.Student> getStudentList() throws android.os.RemoteException;
  201. }

根据类结构图, 其实我们只需要搞明白这2个核心实现方法

1. 静态抽象类 Stub;

2. Stub的静态内部类Proxy ;

Question:  写到这里,提个问题,就是google工程师为什么要把 Stub类设计为抽象类啊?

Answer:   Stub类extends  android.os.Binder  并且 implement 你自定义的AIDL文件中的方法,  它的最终实现是在你的service代码中,  人家google工程师他们只能帮你把模板搭建好, 具体的业务逻辑肯定是自己去实现了.

在服务端中继承IStudentService.Stub这个抽象类, 并在 onBind回调方法中返回IBinder对象

  1. class MyBinder extends IStudentService.Stub{
  2. @Override
  3. public String getString() throws RemoteException {
  4. return "我是从服务端返回的数据: 111";
  5. }
  6. @Override
  7. public void addStudent(Student student) throws RemoteException {
  8. mStudentList.add(student);
  9. }
  10. @Override
  11. public List<Student> getStudentList() throws RemoteException {
  12. return mStudentList;
  13. }
  14. }
  15. @Override
  16. public IBinder onBind(Intent intent) {
  17. Log.e("test", "==服务端==onBind========");
  18. // TODO: Return the communication channel to the service.
  19. return new MyBinder();
  20. }

这个IBinder对象对应的就是客户端中 IBinder  service对象.

public void onServiceConnected(ComponentName componentName, IBinder service)

我们逐个来解析:

public interface IStudentService extends android.os.IInterface

2.1  首先IStudentService.java类继承与 IInterface这个接口

  1. package android.os;
  2. /**
  3. * Base class for Binder interfaces. When defining a new interface,
  4. * you must derive it from IInterface.
  5. Binder接口的基类。当定义新接口时,你必须继承它。
  6. */
  7. public interface IInterface
  8. {
  9. /**
  10. * Retrieve the Binder object associated with this interface.
  11. * You must use this instead of a plain cast, so that proxy objects
  12. * can return the correct result.
  13. 检索与此接口关联的Binder对象。
  14. 必须使用此方法转换,这样代理对象才能返回正确的结果
  15. */
  16. public IBinder asBinder();
  17. }

同时它自己也是一个接口, 所有可以在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对象.

  1. public static com.example.mysevicejava.IStudentService asInterface(android.os.IBinder obj) {
  2. if ((obj == null)) {
  3. return null;
  4. }
  5. // queryLocalInterface是Binder的方法,搜索本地是否有可用的对象
  6. // DESCRIPTOR = "com.example.mysevicejava.IStudentService";
  7. android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  8. //如果有,则强制类型转换并返回
  9. if (((iin != null) && (iin instanceof com.example.mysevicejava.IStudentService))) {
  10. return ((com.example.mysevicejava.IStudentService) iin);
  11. }
  12. // //如果没有,则构造一个IStudentService.Stub.Proxy对象
  13. return new com.example.mysevicejava.IStudentService.Stub.Proxy(obj);
  14. }

2.4   Stub的静态内部类Proxy

通过上面的new com.example.mysevicejava.IStudentService.Stub.Proxy(obj)调用过来的

  1. private static class Proxy implements com.example.mysevicejava.IStudentService{
  2. private android.os.IBinder mRemote;
  3. //构造方法
  4. Proxy(android.os.IBinder remote){
  5. mRemote = remote;
  6. }
  7. @Override public android.os.IBinder asBinder(){
  8. return mRemote;
  9. }
  10. public java.lang.String getInterfaceDescriptor(){
  11. return DESCRIPTOR;
  12. }
  13. .......
  14. .......
  15. }

通过代码,我们知道

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。

客户端的代码中调用

  1. @Override
  2. public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
  3. Log.e("test", " componentName :" + componentName);
  4. mIStudentService = IStudentService.Stub.asInterface(iBinder);
  5. }

我们再回到2.3 asInterface(android.os.IBinder obj) 这个方法中来

asInterface():客户端在ServiceConnection通过IStudentService.Stub.asInterface(IBinder),
会根据是同一进行通信, 还是不同进程通信,返回Stub()实体,或者Stub.Proxy()代理对象

从字面意思看,Stub是存根,Proxy是代理,而这个Stub是谁的存根呢?Proxy又是谁的代理呢?


我理解的是 :  

Stub是 服务端Binder实体的存根.

Proxy则是Stub的代理. 

Stub类: 服务实体,Binder的实现类,服务端一般会实例化一个Binder对象,在服务端onBind中绑定, 客户端asInterface获取到Stub。 这个类在编译aidl文件后自动生成,它继承自Binder,表示它是一个Binder本地对象; 它是一个抽象类,实现了IInterface接口,表明它的子类需要实现Server将要提供的具体能力(即aidl文件中声明的方 法)

Stub.Proxy类: 服务的代理,客户端asInterface获取到Stub.Proxy。 它实现了IInterface接口,说明它是 Binder通信过程的一部分;它实现了aidl中声明的方法,但最终还是交由其中的mRemote成员来处理,说明它是一 个代理对象,mRemote成员实际上就是BinderProxy。供客户端来调用.
通信图:

四. 手写AIDL

我们先来看一下代码目录结构: 

分为4个部分:客户端, 服务端 , 手写AIDL文件, javabean类
 

直接上代码:

1. 客户端ClientActivity.java

  1. /**
  2. * @ProjectName: WriteAIDLTest
  3. * @PackageName: com.example.writeaidltest
  4. * @Description: java类作用描述
  5. * @Author: 作者名
  6. * @CreateDate: 23-3-13 下午1:55
  7. * @Version: 1.0
  8. */
  9. public class ClientActivity extends Activity {
  10. private Intent intent;
  11. private IStudent mIStudent;
  12. //是否绑定成功
  13. boolean mBound = false;
  14. @Override
  15. protected void onCreate(@Nullable Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.activity_main);
  18. intent = new Intent(this, MyServer.class);
  19. Button btn = (Button)findViewById(R.id.button);
  20. btn.setOnClickListener(new View.OnClickListener() {
  21. @Override
  22. public void onClick(View view) {
  23. if(mBound) {
  24. try {
  25. Log.e("test", "mIStudent.getString() 当前线程 :" + Thread.currentThread().getName());
  26. String text = mIStudent.getString();
  27. Log.e("test", "mIStudent.getString() after ");
  28. Toast.makeText(ClientActivity.this, "内容: " + text, Toast.LENGTH_SHORT).show();
  29. } catch (RemoteException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }
  34. });
  35. Button btn1 = (Button)findViewById(R.id.button1);
  36. btn1.setOnClickListener(new View.OnClickListener() {
  37. @Override
  38. public void onClick(View view) {
  39. if(mBound) {
  40. try {
  41. mIStudent.addStudent(new Student(3, "王五"));
  42. } catch (RemoteException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. }
  47. });
  48. Button btn2 = (Button)findViewById(R.id.button2);
  49. btn2.setOnClickListener(new View.OnClickListener() {
  50. @Override
  51. public void onClick(View view) {
  52. if(mBound) {
  53. try {
  54. Log.e("test", "获取服务端所有学生的信息: "+mIStudent.getStudentList());
  55. } catch (RemoteException e) {
  56. e.printStackTrace();
  57. }
  58. }
  59. }
  60. });
  61. }
  62. private ServiceConnection connection = new ServiceConnection() {
  63. @Override
  64. public void onServiceConnected(ComponentName componentName, IBinder service) {
  65. Log.e("test", "===客户端===onServiceConnected=====service是一个什么对象: ="+service.getClass().getCanonicalName());
  66. mBound = true;
  67. mIStudent = Stub.asInterface(service);
  68. Log.e("test", "===客户端 mIStudent是一个什么对象:" + mIStudent.getClass().getCanonicalName());
  69. }
  70. @Override
  71. public void onServiceDisconnected(ComponentName componentName) {
  72. Log.e("test", "====onServiceDisconnected=====");
  73. mBound = false;
  74. }
  75. };
  76. //在onstart方法中 调用 bindservice 绑定服务
  77. @Override
  78. protected void onStart() {
  79. super.onStart();
  80. bindService(intent, connection, Context.BIND_AUTO_CREATE);
  81. }
  82. //在onstop方法中, 调用unbindservice 解绑服务
  83. @Override
  84. protected void onStop() {
  85. super.onStop();
  86. unbindService(connection);
  87. mBound = false;
  88. }
  89. @Override
  90. protected void onDestroy() {
  91. super.onDestroy();
  92. }
  93. }

2.  服务端代码MyServer.java

  1. /**
  2. * @ProjectName: WriteAIDLTest
  3. * @PackageName: com.example.writeaidltest.service
  4. * @Description: java类作用描述
  5. * @Author: 作者名
  6. * @CreateDate: 23-3-13 下午3:12
  7. * @Version: 1.0
  8. */
  9. public class MyServer extends Service {
  10. private List<Student> mStudentList = new ArrayList<>();
  11. @Override
  12. public void onCreate() {
  13. super.onCreate();
  14. mStudentList.add(new Student(1, "张三"));
  15. mStudentList.add(new Student(2, "李四"));
  16. }
  17. @Nullable
  18. @Override
  19. public IBinder onBind(Intent intent) {
  20. Log.e("test", "==服务端==onBind===new MyBinder()是一个什么对象====="+new MyBinder().getClass().getCanonicalName());
  21. //return new MyBinder();
  22. Log.e("test", "==服务端==onBind==myBinder是一个什么对象====="+myBinder.toString());
  23. return myBinder;
  24. }
  25. IBinder myBinder = new Stub() {
  26. @Override
  27. public String getString() throws RemoteException {
  28. return "服务端数据 777";
  29. }
  30. @Override
  31. public void addStudent(Student student) throws RemoteException {
  32. mStudentList.add(student);
  33. }
  34. @Override
  35. public List<Student> getStudentList() throws RemoteException {
  36. return mStudentList;
  37. }
  38. };
  39. class MyBinder extends Stub{
  40. @Override
  41. public String getString() throws RemoteException {
  42. return "服务端数据 111";
  43. }
  44. @Override
  45. public void addStudent(Student student) throws RemoteException {
  46. mStudentList.add(student);
  47. }
  48. @Override
  49. public List<Student> getStudentList() throws RemoteException {
  50. return mStudentList;
  51. }
  52. }
  53. @Override
  54. public void onDestroy() {
  55. Log.e("test", "==服务端=onDestroy=====");
  56. super.onDestroy();
  57. }
  58. }

3.  序列化 Student.java

  1. public class Student implements Parcelable {
  2. private int id;
  3. private String name;
  4. public Student(int id, String name) {
  5. this.id = id;
  6. this.name = name;
  7. }
  8. @Override
  9. public int describeContents() {
  10. return 0;
  11. }
  12. @Override
  13. public void writeToParcel(Parcel dest, int flags) {
  14. dest.writeInt(id);
  15. dest.writeString(name);
  16. }
  17. public void readFromParcel(Parcel parcel) {
  18. this.id = parcel.readInt();
  19. this.name = parcel.readString();
  20. }
  21. public static Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
  22. @Override
  23. public Student createFromParcel(Parcel source) {
  24. return new Student(source);
  25. }
  26. @Override
  27. public Student[] newArray(int size) {
  28. return new Student[0];
  29. }
  30. };
  31. private Student(Parcel in) {
  32. this.id = in.readInt();
  33. this.name = in.readString();
  34. }
  35. @Override
  36. public String toString() {
  37. return "Student{" +
  38. "id=" + id +
  39. ", name='" + name + '\'' +
  40. '}';
  41. }
  42. }

4. 最重要,手动仿写AIDL文件  IStudent.java 

相当于 IStudent.aidl 文件用安卓自带工具生成  IStudent.java 

  1. /**
  2. * @ProjectName: WriteAIDLTest
  3. * @PackageName: com.example.writeaidltest.aidlfile
  4. * @Description: 手动仿写AIDL文件
  5. * @Author: 作者名
  6. * @CreateDate: 23-3-13 下午1:58
  7. * @Version: 1.0
  8. */
  9. public interface IStudent extends android.os.IInterface {
  10. //定义一个DESCRIPTOR
  11. //意图: 为了一个Binder和一个特定服务接口绑定,以对外提供功能,需要给Binder定义一个DESCRIPTOR描述,表示我这个Binder是提供特定功能链接的,不是随便可以用的
  12. public static final java.lang.String DESCRIPTOR = "com.example.writeaidltest.aidlfile.IStudentService";
  13. //定义操作数据的方法
  14. //1. 从服务端获取一个简单的字符串
  15. String getString() throws RemoteException;
  16. //2. 客户端往服务端 添加student对象
  17. void addStudent(Student student) throws RemoteException;
  18. //3. 客户端从服务段获取 所有Student的信息
  19. List<Student> getStudentList() throws RemoteException;
  20. //定义方法的id号
  21. static final int TRANSACTION_getString = IBinder.FIRST_CALL_TRANSACTION + 0;
  22. static final int TRANSACTION_addStudent = IBinder.FIRST_CALL_TRANSACTION + 1;
  23. static final int TRANSACTION_getStudentList = IBinder.FIRST_CALL_TRANSACTION + 2;
  24. }

手动仿写AIDL文件   Stub.java

抽象类 Stub

  1. public abstract class Stub extends android.os.Binder implements IStudent{
  2. //构造方法
  3. public Stub() {
  4. this.attachInterface(this, DESCRIPTOR);
  5. }
  6. public static IStudent asInterface(IBinder obj) {
  7. if (obj == null) {
  8. return null;
  9. }
  10. IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  11. if (iin != null && (iin instanceof IStudent)) {
  12. return (IStudent)iin;
  13. }
  14. // 传入binder对象,返回一个服务代理对象
  15. return new Proxy(obj);
  16. }
  17. @SuppressLint("NewApi")
  18. @Override
  19. protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
  20. switch (code) {
  21. case INTERFACE_TRANSACTION:
  22. reply.writeString(DESCRIPTOR);
  23. return true;
  24. case TRANSACTION_getString:
  25. // 获取IBinder接口标志
  26. data.enforceInterface(DESCRIPTOR);
  27. //这个是服务端自己实现getString方法,获取返回值
  28. String stringResult = this.getString();
  29. Log.e("test", " stub onTransact 当前线程: "+Thread.currentThread().getName());
  30. reply.writeNoException();
  31. reply.writeString(stringResult);
  32. return true;
  33. case TRANSACTION_addStudent:
  34. // 获取IBinder接口标志
  35. data.enforceInterface(DESCRIPTOR);
  36. // 获取传入的Student对象
  37. Student arg0 = null;
  38. if (data.readInt() != 0) {
  39. arg0 = Student.CREATOR.createFromParcel(data);
  40. }
  41. this.addStudent(arg0);
  42. reply.writeNoException();
  43. return true;
  44. case TRANSACTION_getStudentList:
  45. data.enforceInterface(DESCRIPTOR);
  46. //
  47. List<Student> studentList = null;
  48. studentList = this.getStudentList();
  49. reply.writeNoException();
  50. reply.writeTypedList(studentList);
  51. return true;
  52. }
  53. return super.onTransact(code, data, reply, flags);
  54. }
  55. @Override
  56. public IBinder asBinder() {
  57. return this;
  58. }
  59. }

手动仿写  Proxy.java 

  1. public class Proxy implements IStudent{
  2. private IBinder mRemote;
  3. public Proxy(IBinder remote) {
  4. mRemote = remote;
  5. Log.e("test", "===Proxy中 mRemote 是一个什么对象: " + mRemote.getClass().getCanonicalName());
  6. }
  7. @Override
  8. public String getString() throws RemoteException {
  9. Parcel data = Parcel.obtain(); // 跨进程传输数据对象
  10. Parcel reply = Parcel.obtain(); // 跨进程传输返回结果
  11. java.lang.String _result;
  12. try {
  13. data.writeInterfaceToken(DESCRIPTOR);
  14. // 调Stub的onTransact方法进行Stub.TRANSACTION_getString,远端返回
  15. Log.e("test", "mRemote transact 当前线程 :" + Thread.currentThread().getName());
  16. mRemote.transact(TRANSACTION_getString, data, reply, 0);
  17. reply.readException();
  18. _result = reply.readString();
  19. }finally {
  20. data.recycle();
  21. reply.recycle();
  22. }
  23. return _result;
  24. }
  25. @Override
  26. public void addStudent(Student student) throws RemoteException {
  27. Parcel data = Parcel.obtain(); // 跨进程传输数据对象
  28. Parcel reply = Parcel.obtain(); // 跨进程传输返回结果
  29. try{
  30. // 写入IBinder接口标志,一般为全类名,用户数据校验
  31. data.writeInterfaceToken(DESCRIPTOR);
  32. if (student != null){
  33. //写入数据
  34. data.writeInt(1);
  35. student.writeToParcel(data, 0);
  36. } else {
  37. data.writeInt(0);
  38. }
  39. // 调Stub的onTransact方法进行Stub.TRANSACTION_addBook处理,远端返回
  40. mRemote.transact(Stub.TRANSACTION_addStudent, data, reply, 0);
  41. reply.readException();
  42. } finally {
  43. data.recycle();
  44. reply.recycle();
  45. }
  46. }
  47. @Override
  48. public List<Student> getStudentList() throws RemoteException {
  49. Parcel data = Parcel.obtain(); // 跨进程传输数据对象
  50. Parcel reply = Parcel.obtain(); // 跨进程传输返回结果
  51. List<Student> result;
  52. try {
  53. // 写入IBinder接口标志,一般为全类名,用户数据校验
  54. data.writeInterfaceToken(DESCRIPTOR);
  55. // 调Stub的onTransact方法进行Stub.TRANSACTION_getStudentList,远端返回
  56. mRemote.transact(TRANSACTION_getStudentList, data, reply, 0);
  57. reply.readException();
  58. result = reply.createTypedArrayList(Student.CREATOR);
  59. } finally {
  60. reply.recycle();
  61. data.recycle();
  62. }
  63. return result;
  64. }
  65. // 返回Stub类传入的Binder对象
  66. @Override
  67. public IBinder asBinder() {
  68. return mRemote;
  69. }
  70. public java.lang.String getInterfaceDescriptor() {
  71. return DESCRIPTOR;
  72. }
  73. }

清单AndroidManifest.xml 文件
 

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.example.writeaidltest">
  4. <application
  5. android:allowBackup="true"
  6. android:icon="@mipmap/ic_launcher"
  7. android:label="@string/app_name"
  8. android:roundIcon="@mipmap/ic_launcher_round"
  9. android:supportsRtl="true"
  10. android:theme="@style/Theme.WriteAIDLTest">
  11. <activity android:name=".client.ClientActivity">
  12. <intent-filter>
  13. <action android:name="android.intent.action.MAIN" />
  14. <category android:name="android.intent.category.LAUNCHER" />
  15. </intent-filter>
  16. </activity>
  17. <!-- service 运行在另外一个进程中 -->
  18. <service
  19. android:name=".service.MyServer"
  20. android:exported="true"
  21. android:enabled="true"
  22. android:process=":remote">
  23. <intent-filter>
  24. <action android:name="com.my.binder" />
  25. <category android:name="android.intent.category.DEFAULT" />
  26. </intent-filter>
  27. </service>
  28. </application>

上面的例子是模拟进程间通信的整个过程,可以通过log看出客户端发送数据给服务端,然后服务端处理之后再返回给客户端的整个流程。

大家可以通过这个Demo去学习AIDL的原理,供参考!

Demo 已上传: https://download.csdn.net/download/u012514113/87906468

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/122796
推荐阅读
相关标签
  

闽ICP备14008679号