当前位置:   article > 正文

手写一个AIDL_android aidl 手写实现

android aidl 手写实现

客户端demo:https://github.com/hewind/AidlClientTest

服务端demo:https://github.com/hewind/AidlServerTest

实现功能:增加人员、删除人员、获取人员信息;

一、客户端

1、创建PersonBean实体类

  1. public class PersonBean implements Parcelable {
  2. private String name;
  3. public PersonBean(String name) {
  4. this.name = name;
  5. }
  6. public String getName() {
  7. return name == null ? "" : name;
  8. }
  9. public void setName(String name) {
  10. this.name = name;
  11. }
  12. @Override
  13. public String toString() {
  14. return "PersonBean{" + "name='" + name + '\'' + '}';
  15. }
  16. protected PersonBean(Parcel in) {
  17. name = in.readString();
  18. }
  19. public static final Creator<PersonBean> CREATOR = new Creator<PersonBean>() {
  20. @Override
  21. public PersonBean createFromParcel(Parcel in) {
  22. return new PersonBean(in);
  23. }
  24. @Override
  25. public PersonBean[] newArray(int size) {
  26. return new PersonBean[size];
  27. }
  28. };
  29. @Override
  30. public int describeContents() {
  31. return 0;
  32. }
  33. @Override
  34. public void writeToParcel(Parcel parcel, int i) {
  35. parcel.writeString(name);
  36. }
  37. //删除使用
  38. @Override
  39. public boolean equals(@Nullable Object obj) {
  40. if (this == obj){//自反性
  41. return true;
  42. }
  43. if (!(obj instanceof PersonBean)){//instanceof比较判断是否是同一类或者子父类关系
  44. return false;
  45. }
  46. if (this.name.equals(((PersonBean) obj).getName())){//判断是同一类或者子父类关系,再将Object类型强转为Students
  47. return true;
  48. }
  49. return false;
  50. }
  51. @Override
  52. public int hashCode() {
  53. return name.hashCode();
  54. }
  55. }

PersonBean实现Parcelable接口,目的为了跨进程传输,重写equals和hashCode方法目的为了使用删除;

2、创建PersonManagerInterface接口

  1. public interface PersonManagerInterface extends IInterface {
  2. //添加人数
  3. void addPerson(PersonBean personBean) throws RemoteException;
  4. //删除人数
  5. void deletePerson(PersonBean personBean) throws RemoteException;
  6. //获取人数
  7. List<PersonBean> getPerson() throws RemoteException;
  8. }

创建PersonManagerInterface接口,并实现IInterface接口,只有实现IInterface接口,才具备跨进程传输的基础能力,另外如果我们使用Android Studio自带的创建AIDL生成的aidl文件,也是继承了该IInterface接口,这里自己手动创建并继承效果是一样的。

3、创建Proxy代理类

  1. public class Proxy implements PersonManagerInterface {
  2. //远程binder对象
  3. private IBinder iBinder;
  4. //Binder ID
  5. private static final String DESCRIPTOR = "com.example.aidlservertest.Proxy.PersonManagerInterface";
  6. public Proxy(IBinder iBinder) {
  7. this.iBinder = iBinder;
  8. }
  9. //增加人数实现
  10. @Override
  11. public void addPerson(PersonBean personBean) throws RemoteException {
  12. Parcel data = Parcel.obtain();
  13. Parcel replay = Parcel.obtain();
  14. try {
  15. data.writeInterfaceToken(DESCRIPTOR);
  16. if (personBean != null){
  17. data.writeInt(1);
  18. personBean.writeToParcel(data,0);
  19. }else {
  20. data.writeInt(0);
  21. }
  22. iBinder.transact(Stub.TRANSAVTION_addperson,data,replay,0);
  23. replay.readException();
  24. }finally {
  25. replay.recycle();
  26. data.recycle();
  27. }
  28. }
  29. //删除人数实现
  30. @Override
  31. public void deletePerson(PersonBean personBean) throws RemoteException {
  32. Parcel data = Parcel.obtain();
  33. Parcel replay = Parcel.obtain();
  34. try {
  35. data.writeInterfaceToken(DESCRIPTOR);
  36. if (personBean != null){
  37. data.writeInt(1);
  38. personBean.writeToParcel(data,0);
  39. }else {
  40. data.writeInt(0);
  41. }
  42. iBinder.transact(Stub.TRANSAVTION_deleteperson,data,replay,0);
  43. replay.readException();
  44. }finally {
  45. replay.recycle();
  46. data.recycle();
  47. }
  48. }
  49. //查询人数实现
  50. @Override
  51. public List<PersonBean> getPerson() throws RemoteException {
  52. Parcel data = Parcel.obtain();
  53. Parcel replay = Parcel.obtain();
  54. List<PersonBean> result;
  55. try {
  56. //写入一个校验
  57. data.writeInterfaceToken(DESCRIPTOR);
  58. //客户端调用到这个方法,走到iBinder.transact,此时会进入系统层处理,处理结果通过调用Stub的transact方法返回,系统层处理过程会阻塞在这行代码,直到处理完成,
  59. iBinder.transact(Stub.TRANSAVTION_getpersons,data,replay,0);
  60. //上面一行代码在系统处理成功后,返回结果,由于Stub的transact方法写入了一个【reply.writeNoException()】,这里reply进行读取异常
  61. replay.readException();
  62. //这里是Stub的transact方法处理返回的结果
  63. result = replay.createTypedArrayList(PersonBean.CREATOR);
  64. }finally {
  65. replay.recycle();
  66. data.recycle();
  67. }
  68. return result;
  69. }
  70. /**
  71. * 方法说明:返回当前获取到的服务端的IBander
  72. * 日期:2020-09-09 10:31
  73. */
  74. @Override
  75. public IBinder asBinder() {
  76. return iBinder;
  77. }
  78. }
  1. Proxy在AIDL通信中承担着发送信息的角色;
  2. Proxy实现了PersonManagerInterface接口,同时实现asBinder方法,该方法返回一个iBinder对象,该iBinder对象由Stub类实例化Proxy并传入iBinder对象;
  3. DESCRIPTOR为BinderID,一般由包名+PersonManagerInterface组成;
  4. 获取人数信息getPerson方法中data为要传送的数据,reply为接收返回的数据;data.writeInterfaceToken(DESCRIPTOR)方法为写入binderID作为校验,服务端的Stub方法收到后也会进行一个校验;接下来开始调用iBinder的transact方法,该方法会直接进入系统层处理,最终会调用到Binder驱动,然后通过Binder调用服务端的Stub的ontTransact方法建立起一个完整的沟通机制;另外在调用该方法时系统会阻塞线程进入等待,直到返回处理结果;

4、创建Stub类

  1. public abstract class Stub extends Binder implements PersonManagerInterface {
  2. //Binder ID
  3. private static final String DESCRIPTOR = "com.example.aidlservertest.Proxy.PersonManagerInterface";
  4. public Stub() {
  5. //attachInterface方法:向BinderService注册Binder服务。只有注册了binder,客户端才能查询到有这个binder对象,并使用它
  6. this.attachInterface(this,DESCRIPTOR);
  7. }
  8. @Override
  9. public IBinder asBinder() {
  10. return this;
  11. }
  12. //将服务端的Binder对象准换成客户端所需要的AIDL接口对象,
  13. public static PersonManagerInterface asInterface(IBinder iBinder){
  14. if ((iBinder==null)) {
  15. return null;
  16. }
  17. //查询当前进程,如果客户端和服务端位于同一进程,那么此方法返回的就是当前进程的Stub对象本身,否则返回服务端进程的Stub.proxy对象(服务端也有该Stub类)
  18. IInterface iin = iBinder.queryLocalInterface(DESCRIPTOR);
  19. if ((iin != null) && (iin instanceof PersonManagerInterface)) {
  20. return (PersonManagerInterface)iin;
  21. }
  22. //返回服务端的Stub.proxy对象
  23. return new Proxy(iBinder);
  24. }
  25. //这个方法运行在服务端中的Binder线程池当中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。
  26. @Override
  27. protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
  28. switch (code){
  29. case INTERFACE_TRANSACTION:
  30. reply.writeString(DESCRIPTOR);
  31. return true;
  32. case TRANSAVTION_addperson://增加人数
  33. //返回一个校验
  34. data.enforceInterface(DESCRIPTOR);
  35. PersonBean personBean = null;
  36. if (data.readInt() != 0){
  37. //读取PersonBean
  38. personBean = PersonBean.CREATOR.createFromParcel(data);
  39. }
  40. //接口方法回调出去,这里最终会走到服务端的Service类的IBinder回调中
  41. this.addPerson(personBean);
  42. //返回一个无异常
  43. reply.writeNoException();
  44. return true;
  45. case TRANSAVTION_deleteperson://删除人数
  46. data.enforceInterface(DESCRIPTOR);
  47. PersonBean personBean2 = null;
  48. if (data.readInt() != 0){
  49. personBean2 = PersonBean.CREATOR.createFromParcel(data);
  50. }
  51. this.deletePerson(personBean2);
  52. reply.writeNoException();
  53. return true;
  54. case TRANSAVTION_getpersons://获取人数
  55. data.enforceInterface(DESCRIPTOR);
  56. List<PersonBean> result = this.getPerson();
  57. reply.writeNoException();
  58. reply.writeTypedList(result);
  59. return true;
  60. }
  61. return super.onTransact(code, data, reply, flags);
  62. }
  63. //使用int型代替字符串传递来标识调用的是哪一个方法,属于性能优化
  64. public static final int TRANSAVTION_getpersons = IBinder.FIRST_CALL_TRANSACTION;
  65. public static final int TRANSAVTION_addperson = IBinder.FIRST_CALL_TRANSACTION + 1;
  66. public static final int TRANSAVTION_deleteperson = IBinder.FIRST_CALL_TRANSACTION + 2;
  67. }
  1. Stub在AIDL通信中承担着接收信息的角色;
  2. Stub类继承了Binder,同时实现了PersonManagerInterface接口;
  3. 无参构造器中,Stub类调用了一个attachInterface方法,传入了当前对象以及BinderID,该方法是向BinderService注册Binder服务,只有注册了Binder,客户端才能查询到这个Binder对象并使用它;
  4. asBinder方法返回的是当前对象,实际上跟Proxy中asBinder方法返回的是同一个Binder对象;
  5. asInterface方法是将服务端的BInder对象转换成客户端所需要的AIDL接口对象,iBinder.queryLocalInterface(DESCRIPTOR)方法会先查询一下本地进程的DESCRIPTOR是否为null,不为null的话就直接返回PersonManagerInterface接口对象;否则就实例化Proxy,并传入iBinder对象;
  6. onTransact方法即为BInder驱动处理后返回给服务端的出口,这个方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,请求经过BInder处理,再交给该方法;
  7. 其中code参数为方法代理名称,使用数字来代替客户端想要调用的某个方法名,如果有多个方法名,会在IBinder.FIRST_CALL_TRANSACTION默认上进行加1,以此类推;

5、客户端绑定服务

  1. public class MainActivity extends AppCompatActivity {
  2. private Button button,button2,button3;
  3. private TextView textView;
  4. private PersonManagerInterface personManagerInterface;
  5. @Override
  6. protected void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.activity_main);
  9. prePareAidl();
  10. textView = findViewById(R.id.textview);
  11. button = findViewById(R.id.button);
  12. button2 = findViewById(R.id.button2);
  13. button3 = findViewById(R.id.button3);
  14. //添加人员
  15. button.setOnClickListener(new View.OnClickListener() {
  16. @Override
  17. public void onClick(View view) {
  18. PersonBean personBean = new PersonBean();
  19. personBean.setName("张三");
  20. try {
  21. personManagerInterface.addPerson(personBean);
  22. } catch (RemoteException e) {
  23. e.printStackTrace();
  24. }
  25. getPerson();
  26. }
  27. });
  28. //删除人员
  29. button2.setOnClickListener(new View.OnClickListener() {
  30. @Override
  31. public void onClick(View view) {
  32. PersonBean personBean = new PersonBean();
  33. personBean.setName("张三");
  34. try {
  35. personManagerInterface.deletePerson(personBean);
  36. } catch (RemoteException e) {
  37. e.printStackTrace();
  38. }
  39. getPerson();
  40. }
  41. });
  42. //获取人员
  43. button3.setOnClickListener(new View.OnClickListener() {
  44. @Override
  45. public void onClick(View view) {
  46. getPerson();
  47. }
  48. });
  49. }
  50. /**
  51. * 方法说明:获取Person人数
  52. * 日期:2020-09-11 16:36
  53. */
  54. private void getPerson() {
  55. try {
  56. List<PersonBean> list = personManagerInterface.getPerson();
  57. String str = "";
  58. for (PersonBean p:list){
  59. str += p.getName()+", ";
  60. }
  61. textView.setText(str);
  62. } catch (RemoteException e) {
  63. e.printStackTrace();
  64. }
  65. }
  66. /**
  67. * 方法说明:通过绑定远程service,初始化远程iBinder实例
  68. * 日期:2020-09-09 17:14
  69. */
  70. private void prePareAidl() {
  71. Intent intent = new Intent();
  72. intent.setClassName("com.example.aidlservertest","com.example.aidlservertest.Service.PersonService");
  73. bindService(intent,MyServerConnection, Context.BIND_AUTO_CREATE);
  74. }
  75. /**
  76. * 方法说明:创建ServiceConnection
  77. * 日期:2020-09-09 17:15
  78. */
  79. private ServiceConnection MyServerConnection = new ServiceConnection() {
  80. @Override
  81. public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
  82. System.out.println("---客户端 建立服务链接; Thread: "+Thread.currentThread().getName());
  83. //初始化远程iBinder实例,将iBinder转成远程服务代理对象,也就是PersonManagerProxy类对象,并调用它的方法
  84. personManagerInterface = Stub.asInterface(iBinder);
  85. }
  86. @Override
  87. public void onServiceDisconnected(ComponentName componentName) {
  88. System.out.println("---客户端 断开服务链接; Thread: "+Thread.currentThread().getName());
  89. }
  90. };
  91. }
  1. 绑定服务中,Intent中传入的两个参数,一个是服务端的包名,一个是服务端Service的类路径;
  2. ServiceConnection类中onServiceConnected方法返回了一个iBinder对象,此时通过调用Stub.asInterface(iBinder)将iBInder转为服务端代理对象,也就是PersonManagerProxy接口实现类对象,并调用它的方法;

二、服务端

1、拷贝通信文件

将客户端的PersonManagerProxy、Proxy、Stub、PersonBean三个类,原封不动拷贝到服务端工程下,三个类所在目录也要同客户端一致;

2、创建Service

  1. public class PersonService extends Service {
  2. private List<PersonBean> list = new ArrayList<>();
  3. @Override
  4. public int onStartCommand(Intent intent, int flags, int startId) {
  5. System.out.println("---服务端 onStartCommand; Thread: "+Thread.currentThread().getName());
  6. return super.onStartCommand(intent, flags, startId);
  7. }
  8. @Nullable
  9. @Override
  10. public IBinder onBind(Intent intent) {
  11. System.out.println("---服务端 onBind; Thread: "+Thread.currentThread().getName());
  12. return mIBinder;
  13. }
  14. /**
  15. * 方法说明:
  16. * 日期:2020-09-09 11:26
  17. */
  18. private IBinder mIBinder = new Stub(){
  19. @Override
  20. public void addPerson(PersonBean personBean) throws RemoteException {
  21. if (personBean != null){
  22. list.add(personBean);
  23. }
  24. System.out.println("---服务端 addPerson; Thread: "+Thread.currentThread().getName()+", list: "+list);
  25. }
  26. @Override
  27. public void deletePerson(PersonBean personBean) throws RemoteException {
  28. list.remove(personBean);
  29. System.out.println("---服务端 deletePerson; Thread: "+Thread.currentThread().getName()+", list: "+list);
  30. }
  31. @Override
  32. public List<PersonBean> getPerson() throws RemoteException {
  33. System.out.println("---服务端 getPerson; Thread: "+Thread.currentThread().getName()+", list: "+list);
  34. return list;
  35. }
  36. };
  37. }
  1. Service类中的onBind方法返回了一个IBinder对象,这里在Service类中实例化一个Stub对象,因为Stub继承了Binder,同时实现增加、删除、查询方法,在这三个方法中进行实现相应的功能,客户端通过Proxy——>Binder.transact——>Binder驱动——>服务端Stub.onTransact——服务端new Stub;形成一个完整的通信机制

3、服务端开启服务

  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. startService(new Intent(this, PersonService.class));
  7. }
  8. }

使用startService开启服务;

4、注册服务

  1. <service android:name="com.example.aidlservertest.Service.PersonService"
  2. android:enabled="true"
  3. android:exported="true"/>

到此整个手动创建AIDL工程已经结束,测试的时候,需要先运行服务端,再运行客户端;

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号