android-aidl4

转:Android Aidl的使用_android aidl使用-CSDN博客
一.准备

Parcelable,可以理解成只是把car整个对象在aidl中进行传递,就理解成一个car的一个类吧,和其他类使用一样就行了,回调:把接口作为参数放在函数参数中。接口的函数传递相关信息,注册方式是把接口放在自己的函数中,然后去调用接口的函数。回调方真正实现接口的函数。

Aidl 实现跨进程通信的步骤,大致为:

1.确认要传入的数据,序列化数据类;

2.创建 Aidl 接口;

3.服务端 Service 实现 Aidl 的接口;

4.客户端绑定服务端,与服务端通信。

本例包名:com.test.relearnaidl

1.确认要传入的数据,序列化实体数据类

Aidl 支持的数据类型有:

  • 八种基本数据类型:byte、char、short、int、long、float、double、boolean
  • String,CharSequence
  • 实现了Parcelable接口的数据类型
  • List类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
  • Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象

AIDL参数TAG 有 in、out、inout 三种,基本类型默认为in,自定义类型需显示声明

  • 当out时,需要空参数构造方法
  • 当 out或inout 时,自定义类型需手动实现

public void readFromParcel(Parcel desc) {

name = desc.readString();

}

实际开发中,我们要传入的数据可能是 JavaBean 类型的,需要先进行序列化,Android 的序列化推荐用 Parcelable 。

序列化后,本例的 Car 类就可以通过 Aidl 传输了。

复制代码
  1. package com.test.relearnaidl.aidl;

  2. import android.os.Parcel;

  3. import android.os.Parcelable;

  4. import androidx.annotation.NonNull;

  5. public class Car implements Parcelable {

  6. private int id;

  7. private String name;

  8. public Car(int id, String name){

  9. this.id = id;

  10. this.name = name;

  11. }

  12. protected Car(Parcel in) {

  13. id = in.readInt();

  14. name = in.readString();

  15. }

  16. public int getId() {

  17. return id;

  18. }

  19. public void setId(int id) {

  20. this.id = id;

  21. }

  22. public String getName() {

  23. return name;

  24. }

  25. public void setName(String name) {

  26. this.name = name;

  27. }

  28. public static final Creator<Car> CREATOR = new Creator<Car>() {

  29. @Override

  30. public Car createFromParcel(Parcel in) {

  31. return new Car(in);

  32. }

  33. @Override

  34. public Car[] newArray(int size) {

  35. return new Car[size];

  36. }

  37. };

  38. @Override

  39. public int describeContents() {

  40. return 0;

  41. }

  42. @Override

  43. public void writeToParcel(Parcel dest, int flags) {

  44. dest.writeInt(id);

  45. dest.writeString(name);

  46. }

  47. @NonNull

  48. @Override

  49. public String toString() {

  50. return String.format("[id:%d, name:%s]",id, name);

  51. }

  52. }

我们写好参数后,直接代码补全生成序列化的一系列方法了。

2.创建 Aidl 接口
2.1 新建 aidl 文件夹

在 project 视图下,在 main 目录新建 Aidl File ,会生成一个 Aidl 文件夹,用来存放 aidl 文件。

2.2 编写 aidl 接口

新建 ICarManager.aidl 文件, 本例中,只添加获取和增加的接口,

复制代码
  1. // ICarManager.aidl

  2. package com.test.relearnaidl.aidl;

  3. import com.test.relearnaidl.aidl.Car;

  4. // Declare any non-default types here with import statements

  5. interface ICarManager {

  6. /**

  7. * Demonstrates some basic types that you can use as parameters

  8. * and return values in AIDL.

  9. */

  10. List<Car> getCarList();

  11. void addNewCar(in Car car);

  12. }

因为我们用的是自定义的 Parcelable 对象 Car,所以还需要编写一个 Car.aidl ,并声明为 Parcelable 类型。

复制代码
  1. package com.test.relearnaidl.aidl;

  2. parcelable Car;

需要注意的是,数据类 和 aidl文件 的包的路径(或者说目录结构)要对应上

本例包名:com.test.relearnaidl ,

我在 java 目录下新建了一个文件夹aidl来存放 Car 类,

所以 aidl 目录下也需要新建 aidl 文件夹来存放这两个 aidl 文件;

否则会报错 couldn't find import for class 。

3.服务端实现
3.1 实现 aidl 接口

其实就是 onBind 中返回一个 Binder 对象,这个 Binder 对象继承 ICarManager.Stub() 并实现了它内部的方法。

复制代码
  1. package com.test.relearnaidl.service;

  2. import android.app.Service;

  3. import android.content.Intent;

  4. import android.os.Binder;

  5. import android.os.IBinder;

  6. import android.os.RemoteException;

  7. import androidx.annotation.Nullable;

  8. import com.test.relearnaidl.aidl.Car;

  9. import com.test.relearnaidl.aidl.ICarManager;

  10. import java.util.List;

  11. import java.util.concurrent.CopyOnWriteArrayList;

  12. public class CarManagerService extends Service {

  13. private CopyOnWriteArrayList<Car> mCarList = new CopyOnWriteArrayList<Car>();

  14. private Binder mBinder = new ICarManager.Stub() {

  15. @Override

  16. public List<Car> getCarList() throws RemoteException {

  17. return mCarList;

  18. }

  19. @Override

  20. public void addNewCar(Car car) throws RemoteException {

  21. mCarList.add(car);

  22. }

  23. };

  24. @Nullable

  25. @Override

  26. public IBinder onBind(Intent intent) {

  27. return mBinder;

  28. }

  29. @Override

  30. public void onCreate() {

  31. super.onCreate();

  32. mCarList.add(new Car(100, "SUV 100"));

  33. }

  34. @Override

  35. public int onStartCommand(Intent intent, int flags, int startId) {

  36. return super.onStartCommand(intent, flags, startId);

  37. }

  38. }

3.2 服务端配置

既然要跨进程通信,方然要让 Service 运行在独立进程中,配置下,

复制代码
  1. <service android:name=".service.CarManagerService"

  2. android:process=":remote">

  3. </service>

还有一点,数据处理,简单的数据可以使用 CopyOnWriteArrayList 或者 ConcurrentHashMap 。

4.客户端实现

写个简单的页面,几个按钮分别是 绑定服务端、获取数据、新增数据。

绑定服务端:用 bindService 的方式,绑定成功后将服务端返回的 Binder 转换成 aidl 接口,这样就可以调用服务端的方法了。

这样,客户端就可以获取和新增数据了。


客户端监听数据变化

如服务端数据有更新,客户端怎么及时知道呢,来探索下。

流程为:

  • 1.新增一个 aidl 接口;
  • 2.服务端修改;
  • 3.客户端注册监听。
1.新增一个 aidl 接口

首先,在 aidl 文件夹下新建一个 aidl 文件 IOnNewCarAddListener.aidl ,

复制代码
  1. package com.test.relearnaidl.aidl;

  2. import com.test.relearnaidl.aidl.Car;

  3. interface IOnNewCarAddListener{

  4. void onNewCarAdd(in Car newCar);

  5. }

然后修改 ICarManager.aidl ,添加两个方法

复制代码
  1. // ICarManager.aidl

  2. package com.test.relearnaidl.aidl;

  3. import com.test.relearnaidl.aidl.Car;

  4. import com.test.relearnaidl.aidl.IOnNewCarAddListener;

  5. // Declare any non-default types here with import statements

  6. interface ICarManager {

  7. /**

  8. * Demonstrates some basic types that you can use as parameters

  9. * and return values in AIDL.

  10. */

  11. List<Car> getCarList();

  12. void addNewCar(in Car car);

  13. void registerListener(IOnNewCarAddListener listener);

  14. void unregisterListener(IOnNewCarAddListener listener);

  15. }

2.服务端修改

修改的不多,主要是为了适配新加的接口。

  • mBinder 对象实现新增的接口;
  • 新增一个列表 mListenerList 存储注册的监听器,数据变化时通知到 mListenerList 里所有的 listenerList ;
  • 添加一个 addRunnable 模拟数据变化。
复制代码
  1. package com.test.relearnaidl.service;

  2. import android.app.Service;

  3. import android.content.Intent;

  4. import android.os.Binder;

  5. import android.os.IBinder;

  6. import android.os.RemoteException;

  7. import android.util.Log;

  8. import androidx.annotation.Nullable;

  9. import com.test.relearnaidl.aidl.Car;

  10. import com.test.relearnaidl.aidl.ICarManager;

  11. import com.test.relearnaidl.aidl.IOnNewCarAddListener;

  12. import java.util.List;

  13. import java.util.concurrent.CopyOnWriteArrayList;

  14. public class CarManagerService extends Service {

  15. private CopyOnWriteArrayList<Car> mCarList = new CopyOnWriteArrayList<Car>();

  16. private CopyOnWriteArrayList<IOnNewCarAddListener> mListenerList = new CopyOnWriteArrayList<IOnNewCarAddListener>();

  17. private Binder mBinder = new ICarManager.Stub() {

  18. @Override

  19. public List<Car> getCarList() throws RemoteException {

  20. return mCarList;

  21. }

  22. @Override

  23. public void addNewCar(Car car) throws RemoteException {

  24. mCarList.add(car);

  25. onNewCarAdd(car);

  26. }

  27. @Override

  28. public void registerListener(IOnNewCarAddListener listener) throws RemoteException {

  29. if (!mListenerList.contains(listener)) {

  30. mListenerList.add(listener);

  31. } else {

  32. Log.d("luoah", "[CarManagerService] -- registerListener -- this listener already exist");

  33. }

  34. }

  35. @Override

  36. public void unregisterListener(IOnNewCarAddListener listener) throws RemoteException {

  37. if (mListenerList.contains(listener)) {

  38. mListenerList.remove(listener);

  39. } else {

  40. Log.d("luoah", "[CarManagerService] -- unregisterListener -- listener not found");

  41. }

  42. }

  43. };

  44. private void onNewCarAdd(Car car) throws RemoteException{

  45. mCarList.add(car);

  46. for (int j = 0; j < mListenerList.size(); j++){

  47. IOnNewCarAddListener listener = mListenerList.get(j);

  48. listener.onNewCarAdd(car);

  49. }

  50. }

  51. @Nullable

  52. @Override

  53. public IBinder onBind(Intent intent) {

  54. return mBinder;

  55. }

  56. @Override

  57. public void onCreate() {

  58. super.onCreate();

  59. mCarList.add(new Car(100, "SUV_100"));

  60. new Thread(new addRunnable()).start();

  61. }

  62. @Override

  63. public int onStartCommand(Intent intent, int flags, int startId) {

  64. return super.onStartCommand(intent, flags, startId);

  65. }

  66. private class addRunnable implements Runnable{

  67. @Override

  68. public void run() {

  69. try{

  70. Thread.sleep(3000);

  71. } catch (InterruptedException ie){

  72. ie.printStackTrace();

  73. }

  74. try {

  75. Car bcar = new Car(700, "BM_700");

  76. onNewCarAdd(bcar);

  77. } catch (RemoteException e) {

  78. e.printStackTrace();

  79. }

  80. }

  81. }

  82. }

3.客户端修改

成功连接后注册 IOnNewCarAddListener ,退出时反注册。和广播很像。

复制代码
  1. package com.test.relearnaidl;

  2. import androidx.appcompat.app.AppCompatActivity;

  3. import android.content.ComponentName;

  4. import android.content.Intent;

  5. import android.content.ServiceConnection;

  6. import android.os.Bundle;

  7. import android.os.IBinder;

  8. import android.os.RemoteException;

  9. import android.util.Log;

  10. import android.view.View;

  11. import android.widget.Button;

  12. import com.test.relearnaidl.aidl.Car;

  13. import com.test.relearnaidl.aidl.ICarManager;

  14. import com.test.relearnaidl.aidl.IOnNewCarAddListener;

  15. import com.test.relearnaidl.service.CarManagerService;

  16. import java.util.List;

  17. public class MainActivity extends AppCompatActivity implements View.OnClickListener{

  18. private Button mButtonBind, mButtonGet, mButtonAdd;

  19. private ICarManager carManager;

  20. private ServiceConnection mConnection = new ServiceConnection() {

  21. @Override

  22. public void onServiceConnected(ComponentName name, IBinder service) {

  23. carManager = ICarManager.Stub.asInterface(service);

  24. try {

  25. List<Car> conCar = carManager.getCarList();

  26. if (conCar != null && conCar.size() > 0) {

  27. Log.d("luoah", "[MainActivity] -- onServiceConnected -- conCar:" + conCar.toString());

  28. }

  29. carManager.registerListener(clientListener);

  30. } catch (RemoteException rme) {

  31. rme.printStackTrace();

  32. }

  33. }

  34. @Override

  35. public void onServiceDisconnected(ComponentName name) {

  36. try {

  37. carManager.unregisterListener(clientListener);

  38. } catch (RemoteException e) {

  39. e.printStackTrace();

  40. }

  41. }

  42. };

  43. private IOnNewCarAddListener clientListener = new IOnNewCarAddListener.Stub() {

  44. @Override

  45. public void onNewCarAdd(Car newCar) throws RemoteException {

  46. Log.d("luoah", "[MainActivity] -- onNewCarAdd -- newCar:" + newCar.toString());

  47. }

  48. };

  49. @Override

  50. protected void onCreate(Bundle savedInstanceState) {

  51. super.onCreate(savedInstanceState);

  52. setContentView(R.layout.activity_main);

  53. mButtonBind = (Button)findViewById(R.id.button_bind);

  54. mButtonGet = (Button)findViewById(R.id.button_get);

  55. mButtonAdd = (Button)findViewById(R.id.button_add);

  56. mButtonBind.setOnClickListener(this);

  57. mButtonGet.setOnClickListener(this);

  58. mButtonAdd.setOnClickListener(this);

  59. }

  60. @Override

  61. public void onClick(View v) {

  62. switch (v.getId()){

  63. case R.id.button_bind:

  64. Intent intent = new Intent(MainActivity.this, CarManagerService.class);

  65. bindService(intent, mConnection, BIND_AUTO_CREATE);

  66. break;

  67. case R.id.button_get:

  68. try {

  69. List<Car> cars = carManager.getCarList();

  70. if (cars != null && cars.size() > 0) {

  71. Log.d("luoah", "[MainActivity] -- onClickGet -- cars:" + cars.toString());

  72. }

  73. } catch (RemoteException e) {

  74. e.printStackTrace();

  75. }

  76. break;

  77. case R.id.button_add:

  78. try {

  79. carManager.addNewCar(new Car(200, "SUV_200"));

  80. carManager.addNewCar(new Car(300, "SUV_300"));

  81. } catch (RemoteException e) {

  82. e.printStackTrace();

  83. }

  84. break;

  85. default:break;

  86. }

  87. }

  88. @Override

  89. protected void onDestroy() {

  90. super.onDestroy();

  91. if (carManager != null

  92. && carManager.asBinder().isBinderAlive()) {

  93. try {

  94. carManager.unregisterListener(clientListener);

  95. } catch (RemoteException e) {

  96. e.printStackTrace();

  97. }

  98. }

  99. unbindService(mConnection);

  100. }

  101. }

这样,当数据变化时,客户端就可以收到消息了。

But ,按返回键退出应用,log 是

com.test.relearnaidl D/luoah: [CarManagerService] -- unregisterListener -- listener not found

不是同一个 listener 吗,怎么找不到 ?

原因如下,摘抄自 《Android开发艺术探索》

多进程无法奏效,因为 Binder 会把客户端传过来的对象重新转化成一个新的对象。虽然注册和解注册过程中使用的是同一个客户端对象,但是通过 Binder 传递到服务端后,却会产生两个全新的对象。别忘了对象是不能跨进程传递的,对象的跨进程传递本质上是反序列化的过程,这就是为什么 AIDL 中的自定义对象都必须要实现 Parcelable 接口。

解决这个问题,用 RemoteCallbackList


正确添加移除监听

用 RemoteCallbackList 来正确移除注册到服务端的 listener 。

客户端不用修改,修改服务端。

  1. 使用 RemoteCallbackList 代替 CopyOnWriteArrayList ;
  2. 修改注册、反注册方法;
  3. 修改通知 listener 的方法。
1.使用 RemoteCallbackList 代替 CopyOnWriteArrayList
private RemoteCallbackList<IOnNewCarAddListener> mRemoteCallbackList = new RemoteCallbackList<IOnNewCarAddListener>();
2.修改注册、反注册方法;
复制代码
  1. @Override

  2. public void registerListener(IOnNewCarAddListener listener) throws RemoteException {

  3. mRemoteCallbackList.register(listener);

  4. /*if (!mListenerList.contains(listener)) {

  5. mListenerList.add(listener);

  6. } else {

  7. Log.d("luoah", "[CarManagerService] -- registerListener -- this listener already exist");

  8. }*/

  9. }

  10. @Override

  11. public void unregisterListener(IOnNewCarAddListener listener) throws RemoteException {

  12. mRemoteCallbackList.unregister(listener);

  13. /*if (mListenerList.contains(listener)) {

  14. mListenerList.remove(listener);

  15. } else {

  16. Log.d("luoah", "[CarManagerService] -- unregisterListener -- listener not found");

  17. }*/

  18. }

3.修改通知 listener 的方法
复制代码
  1. private void onNewCarAdd(Car car) throws RemoteException{

  2. mCarList.add(car);

  3. /*for (int j = 0; j < mListenerList.size(); j++){

  4. IOnNewCarAddListener listener = mListenerList.get(j);

  5. listener.onNewCarAdd(car);

  6. }*/

  7. int t = mRemoteCallbackList.beginBroadcast();

  8. for (int j = 0; j < t; j++){

  9. IOnNewCarAddListener listener = mRemoteCallbackList.getBroadcastItem(j);

  10. if (listener != null) {

  11. try{

  12. listener.onNewCarAdd(car);

  13. } catch (RemoteException e){

  14. e.printStackTrace();

  15. }

  16. }

  17. }

  18. mRemoteCallbackList.finishBroadcast();

  19. }

再添加了权限判断,没权限的客户端无法获取到 Binder。

注册文件添加权限,

复制代码
  1. <permission android:name="com.test.relearnaidl.permision.ACCESS_CAR_DATA"

  2. android:protectionLevel="normal"/>

服务端 onBind 方法中判断权限,

复制代码
  1. @Nullable

  2. @Override

  3. public IBinder onBind(Intent intent) {

  4. int ticket = checkCallingPermission("com.test.relearnaidl.permision.ACCESS_CAR_DATA");

  5. if (ticket == PackageManager.PERMISSION_DENIED) {

  6. return null;

  7. }

  8. return mBinder;

  9. }

附上终版源码,方便以后查阅。

工程目录

1.AIDL

ICarManager.aidl

复制代码
  1. // ICarManager.aidl

  2. package com.test.relearnaidl.aidl;

  3. import com.test.relearnaidl.aidl.Car;

  4. import com.test.relearnaidl.aidl.IOnNewCarAddListener;

  5. // Declare any non-default types here with import statements

  6. interface ICarManager {

  7. /**

  8. * Demonstrates some basic types that you can use as parameters

  9. * and return values in AIDL.

  10. */

  11. List<Car> getCarList();

  12. void addNewCar(in Car car);

  13. void registerListener(IOnNewCarAddListener listener);

  14. void unregisterListener(IOnNewCarAddListener listener);

  15. }

Car.aidl

复制代码
  1. package com.test.relearnaidl.aidl;

  2. parcelable Car;

IOnNewCarAddListener.aidl

复制代码
  1. package com.test.relearnaidl.aidl;

  2. import com.test.relearnaidl.aidl.Car;

  3. interface IOnNewCarAddListener{

  4. void onNewCarAdd(in Car newCar);

  5. }

2.服务端

CarManagerService.java

复制代码
  1. package com.test.relearnaidl.service;

  2. import android.app.Service;

  3. import android.content.Intent;

  4. import android.os.Binder;

  5. import android.os.IBinder;

  6. import android.os.RemoteCallbackList;

  7. import android.os.RemoteException;

  8. import android.util.Log;

  9. import androidx.annotation.Nullable;

  10. import com.test.relearnaidl.aidl.Car;

  11. import com.test.relearnaidl.aidl.ICarManager;

  12. import com.test.relearnaidl.aidl.IOnNewCarAddListener;

  13. import java.util.List;

  14. import java.util.concurrent.CopyOnWriteArrayList;

  15. public class CarManagerService extends Service {

  16. private CopyOnWriteArrayList<Car> mCarList = new CopyOnWriteArrayList<Car>();

  17. private CopyOnWriteArrayList<IOnNewCarAddListener> mListenerList = new CopyOnWriteArrayList<IOnNewCarAddListener>();

  18. private RemoteCallbackList<IOnNewCarAddListener> mRemoteCallbackList = new RemoteCallbackList<IOnNewCarAddListener>();

  19. private Binder mBinder = new ICarManager.Stub() {

  20. @Override

  21. public List<Car> getCarList() throws RemoteException {

  22. return mCarList;

  23. }

  24. @Override

  25. public void addNewCar(Car car) throws RemoteException {

  26. mCarList.add(car);

  27. onNewCarAdd(car);

  28. }

  29. @Override

  30. public void registerListener(IOnNewCarAddListener listener) throws RemoteException {

  31. mRemoteCallbackList.register(listener);

  32. /*if (!mListenerList.contains(listener)) {

  33. mListenerList.add(listener);

  34. } else {

  35. Log.d("luoah", "[CarManagerService] -- registerListener -- this listener already exist");

  36. }*/

  37. }

  38. @Override

  39. public void unregisterListener(IOnNewCarAddListener listener) throws RemoteException {

  40. mRemoteCallbackList.unregister(listener);

  41. /*if (mListenerList.contains(listener)) {

  42. mListenerList.remove(listener);

  43. } else {

  44. Log.d("luoah", "[CarManagerService] -- unregisterListener -- listener not found");

  45. }*/

  46. }

  47. };

  48. private void onNewCarAdd(Car car) throws RemoteException{

  49. mCarList.add(car);

  50. /*for (int j = 0; j < mListenerList.size(); j++){

  51. IOnNewCarAddListener listener = mListenerList.get(j);

  52. listener.onNewCarAdd(car);

  53. }*/

  54. int t = mRemoteCallbackList.beginBroadcast();

  55. for (int j = 0; j < t; j++){

  56. IOnNewCarAddListener listener = mRemoteCallbackList.getBroadcastItem(j);

  57. if (listener != null) {

  58. try{

  59. listener.onNewCarAdd(car);

  60. } catch (RemoteException e){

  61. e.printStackTrace();

  62. }

  63. }

  64. }

  65. mRemoteCallbackList.finishBroadcast();

  66. }

  67. @Nullable

  68. @Override

  69. public IBinder onBind(Intent intent) {

  70. int ticket = checkCallingPermission("com.test.relearnaidl.permision.ACCESS_CAR_DATA");

  71. if (ticket == PackageManager.PERMISSION_DENIED) {

  72. return null;

  73. }

  74. return mBinder;

  75. }

  76. @Override

  77. public void onCreate() {

  78. super.onCreate();

  79. Log.d("luoah", "[CarManagerService] -- onCreate -- ");

  80. mCarList.add(new Car(100, "SUV_100"));

  81. new Thread(new addRunnable()).start();

  82. }

  83. @Override

  84. public int onStartCommand(Intent intent, int flags, int startId) {

  85. return super.onStartCommand(intent, flags, startId);

  86. }

  87. private class addRunnable implements Runnable{

  88. @Override

  89. public void run() {

  90. try{

  91. Thread.sleep(3000);

  92. } catch (InterruptedException ie){

  93. ie.printStackTrace();

  94. }

  95. try {

  96. Car bcar = new Car(700, "BM_700");

  97. onNewCarAdd(bcar);

  98. } catch (RemoteException e) {

  99. e.printStackTrace();

  100. }

  101. }

  102. }

  103. }

3.客户端

客户端 MainActivity.java 。

目前都是在主线程操作的,实际使用的话,还是用 Handler 等方式来获取数据比较好,防止出现超时出现 ANR 等情况。

复制代码
  1. package com.test.relearnaidl;

  2. import androidx.appcompat.app.AppCompatActivity;

  3. import android.content.ComponentName;

  4. import android.content.Intent;

  5. import android.content.ServiceConnection;

  6. import android.os.Bundle;

  7. import android.os.IBinder;

  8. import android.os.RemoteException;

  9. import android.util.Log;

  10. import android.view.View;

  11. import android.widget.Button;

  12. import com.test.relearnaidl.aidl.Car;

  13. import com.test.relearnaidl.aidl.ICarManager;

  14. import com.test.relearnaidl.aidl.IOnNewCarAddListener;

  15. import com.test.relearnaidl.service.CarManagerService;

  16. import java.util.List;

  17. public class MainActivity extends AppCompatActivity implements View.OnClickListener{

  18. private Button mButtonBind, mButtonGet, mButtonAdd;

  19. private ICarManager carManager;

  20. private ServiceConnection mConnection = new ServiceConnection() {

  21. @Override

  22. public void onServiceConnected(ComponentName name, IBinder service) {

  23. carManager = ICarManager.Stub.asInterface(service);

  24. try {

  25. List<Car> conCar = carManager.getCarList();

  26. if (conCar != null && conCar.size() > 0) {

  27. Log.d("luoah", "[MainActivity] -- onServiceConnected -- conCar:" + conCar.toString());

  28. }

  29. carManager.registerListener(clientListener);

  30. } catch (RemoteException rme) {

  31. rme.printStackTrace();

  32. }

  33. }

  34. @Override

  35. public void onServiceDisconnected(ComponentName name) {

  36. try {

  37. carManager.unregisterListener(clientListener);

  38. } catch (RemoteException e) {

  39. e.printStackTrace();

  40. }

  41. }

  42. };

  43. private IOnNewCarAddListener clientListener = new IOnNewCarAddListener.Stub() {

  44. @Override

  45. public void onNewCarAdd(Car newCar) throws RemoteException {

  46. Log.d("luoah", "[MainActivity] -- onNewCarAdd -- newCar:" + newCar.toString());

  47. }

  48. };

  49. @Override

  50. protected void onCreate(Bundle savedInstanceState) {

  51. super.onCreate(savedInstanceState);

  52. setContentView(R.layout.activity_main);

  53. mButtonBind = (Button)findViewById(R.id.button_bind);

  54. mButtonGet = (Button)findViewById(R.id.button_get);

  55. mButtonAdd = (Button)findViewById(R.id.button_add);

  56. mButtonBind.setOnClickListener(this);

  57. mButtonGet.setOnClickListener(this);

  58. mButtonAdd.setOnClickListener(this);

  59. }

  60. @Override

  61. public void onClick(View v) {

  62. switch (v.getId()){

  63. case R.id.button_bind:

  64. Intent intent = new Intent(MainActivity.this, CarManagerService.class);

  65. bindService(intent, mConnection, BIND_AUTO_CREATE);

  66. break;

  67. case R.id.button_get:

  68. try {

  69. List<Car> cars = carManager.getCarList();

  70. if (cars != null && cars.size() > 0) {

  71. Log.d("luoah", "[MainActivity] -- onClickGet -- cars:" + cars.toString());

  72. }

  73. } catch (RemoteException e) {

  74. e.printStackTrace();

  75. }

  76. break;

  77. case R.id.button_add:

  78. try {

  79. carManager.addNewCar(new Car(200, "SUV_200"));

  80. carManager.addNewCar(new Car(300, "SUV_300"));

  81. } catch (RemoteException e) {

  82. e.printStackTrace();

  83. }

  84. break;

  85. default:break;

  86. }

  87. }

  88. @Override

  89. protected void onDestroy() {

  90. super.onDestroy();

  91. if (carManager != null

  92. && carManager.asBinder().isBinderAlive()) {

  93. try {

  94. carManager.unregisterListener(clientListener);

  95. } catch (RemoteException e) {

  96. e.printStackTrace();

  97. }

  98. }

  99. unbindService(mConnection);

  100. }

  101. }

4.数据

就是 Car 类了

复制代码
  1. package com.test.relearnaidl.aidl;

  2. import android.os.Parcel;

  3. import android.os.Parcelable;

  4. import androidx.annotation.NonNull;

  5. public class Car implements Parcelable {

  6. private int id;

  7. private String name;

  8. public Car(int id, String name){

  9. this.id = id;

  10. this.name = name;

  11. }

  12. protected Car(Parcel in) {

  13. id = in.readInt();

  14. name = in.readString();

  15. }

  16. public int getId() {

  17. return id;

  18. }

  19. public void setId(int id) {

  20. this.id = id;

  21. }

  22. public String getName() {

  23. return name;

  24. }

  25. public void setName(String name) {

  26. this.name = name;

  27. }

  28. public static final Creator<Car> CREATOR = new Creator<Car>() {

  29. @Override

  30. public Car createFromParcel(Parcel in) {

  31. return new Car(in);

  32. }

  33. @Override

  34. public Car[] newArray(int size) {

  35. return new Car[size];

  36. }

  37. };

  38. @Override

  39. public int describeContents() {

  40. return 0;

  41. }

  42. @Override

  43. public void writeToParcel(Parcel dest, int flags) {

  44. dest.writeInt(id);

  45. dest.writeString(name);

  46. }

  47. @NonNull

  48. @Override

  49. public String toString() {

  50. return String.format("[id:%d, name:%s]",id, name);

  51. }

  52. }

5.注册文件和布局文件

注册文件

复制代码
  1. <?xml version="1.0" encoding="utf-8"?>

  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"

  3. xmlns:tools="http://schemas.android.com/tools"

  4. package="com.test.relearnaidl">

  5. <permission android:name="com.test.relearnaidl.permision.ACCESS_CAR_DATA"

  6. android:protectionLevel="normal"/>

  7. <application

  8. android:allowBackup="true"

  9. android:icon="@mipmap/ic_launcher"

  10. android:label="@string/app_name"

  11. android:roundIcon="@mipmap/ic_launcher_round"

  12. android:supportsRtl="true"

  13. android:theme="@style/AppTheme">

  14. <activity android:name=".MainActivity">

  15. <intent-filter>

  16. <action android:name="android.intent.action.MAIN" />

  17. <category android:name="android.intent.category.LAUNCHER" />

  18. </intent-filter>

  19. </activity>

  20. <service android:name=".service.CarManagerService"

  21. android:process=":remote">

  22. </service>

  23. </application>

  24. </manifest>

布局文件

复制代码
  1. <?xml version="1.0" encoding="utf-8"?>

  2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"

  3. xmlns:app="http://schemas.android.com/apk/res-auto"

  4. xmlns:tools="http://schemas.android.com/tools"

  5. android:layout_width="match_parent"

  6. android:layout_height="match_parent"

  7. tools:context=".MainActivity">

  8. <Button

  9. android:id="@+id/button_bind"

  10. android:layout_width="wrap_content"

  11. android:layout_height="wrap_content"

  12. android:text="bind servcie"

  13. app:layout_constraintBottom_toBottomOf="parent"

  14. app:layout_constraintHorizontal_bias="0.494"

  15. app:layout_constraintLeft_toLeftOf="parent"

  16. app:layout_constraintRight_toRightOf="parent"

  17. app:layout_constraintTop_toTopOf="parent"

  18. app:layout_constraintVertical_bias="0.625" />

  19. <Button

  20. android:id="@+id/button_get"

  21. android:layout_width="wrap_content"

  22. android:layout_height="wrap_content"

  23. android:text="get car list"

  24. app:layout_constraintBottom_toBottomOf="parent"

  25. app:layout_constraintHorizontal_bias="0.498"

  26. app:layout_constraintLeft_toLeftOf="parent"

  27. app:layout_constraintRight_toRightOf="parent"

  28. app:layout_constraintTop_toTopOf="parent"

  29. app:layout_constraintVertical_bias="0.733" />

  30. <Button

  31. android:id="@+id/button_add"

  32. android:layout_width="wrap_content"

  33. android:layout_height="wrap_content"

  34. android:text="add new Car"

  35. app:layout_constraintBottom_toBottomOf="parent"

  36. app:layout_constraintHorizontal_bias="0.494"

  37. app:layout_constraintLeft_toLeftOf="parent"

  38. app:layout_constraintRight_toRightOf="parent"

  39. app:layout_constraintTop_toTopOf="parent"

  40. app:layout_constraintVertical_bias="0.838" />

  41. </androidx.constraintlayout.widget.ConstraintLayout>


使用linkToDeath对AIDL双向死亡监听

概述

在使用service中进行AIDL交互时候,如果服务端或者客户端意外停止,会抛出异常android.os.DeadObjectException , 这时候我们就需要双向监听服务端和客户端的异常停止,并重新绑定服务

linkToDeath的使用

linkToDeath 为Binder对象添加死亡代理。

unlinkToDeath 取消死亡代理

客户端

首先我们需要创建一个DeathRecipient对象

复制代码
  1. private IBinder.DeathRecipient mDeathProxy = new IBinder.DeathRecipient() {

  2. @Override

  3. public void binderDied() {

  4. //监听死亡,重新绑定

  5. Log.d("zkq", "服务端崩溃,需要重新绑定");

  6. mBinder.asBinder().unlinkToDeath(mDeathProxy, 0);

  7. }

  8. };

在service绑定成功以后,给服务绑定死亡代理 ,当服务端异常停止以后,我们会收到binderDied回调,并在这里重新绑定服务

复制代码
  1. private ServiceConnection conn = new ServiceConnection() {

  2. @Override

  3. public void onServiceConnected(ComponentName name, IBinder iBinder) {

  4. Log.d("zkq", " onServiceConnected = " + iBinder);

  5. mBinder = IMyAidlInterface.Stub.asInterface(iBinder);

  6. try {

  7. mBinder.asBinder().linkToDeath(mDeathProxy, 0);

  8. }catch (RemoteException e){

  9. Log.e("zkq", "onServiceConnected: linkToDeath error");

  10. }

  11. try {

  12. mBinder.setCallback(mICallBack);

  13. } catch (RemoteException e) {

  14. e.printStackTrace();

  15. }

  16. }

  17. @Override

  18. public void onServiceDisconnected(ComponentName name) {

  19. Log.e("zkq", " onServiceDisconnected = " + name);

  20. }

  21. };

绑定服务

复制代码
  1. private void bind() {

  2. Intent intent = new Intent();

  3. intent.setAction(MyService.ACTION);

  4. intent.setPackage(getPackageName());

  5. boolean ret = bindService(intent, conn, Context.BIND_AUTO_CREATE);

  6. Log.d("zkq", " ret = " + ret);

  7. }

服务端

相应的在服务端,添加客户端的死亡监听,我们只需要在binderDied中,移除客户端的回调

复制代码
  1. IMyAidlInterface.Stub myAidlInterface = new IMyAidlInterface.Stub() {

  2. @Override

  3. public void setCallback(ICallBack var1) throws RemoteException {

  4. var1.asBinder().linkToDeath(new DeathRecipient() {

  5. @Override

  6. public void binderDied() {

  7. Log.d("zkq","客户端崩溃,移除回调");

  8. mBinder.asBinder().unlinkToDeath(this, 0);

  9. }

  10. },0);

  11. }

  12. };

完整服务端代码如下:

复制代码
  1. public class MyService extends Service {

  2. public static final String ACTION = "com.zkq.autofly.action.START_SERVICE";

  3. IMyAidlInterface mBinder;

  4. public MyService() {

  5. }

  6. IMyAidlInterface.Stub myAidlInterface = new IMyAidlInterface.Stub() {

  7. @Override

  8. public void setCallback(ICallBack var1) throws RemoteException {

  9. var1.asBinder().linkToDeath(new DeathRecipient() {

  10. @Override

  11. public void binderDied() {

  12. Log.d("zkq","客户端崩溃,需要重新绑定");

  13. }

  14. },0);

  15. }

  16. };

  17. @Override

  18. public IBinder onBind(Intent intent) {

  19. if (intent.getAction().equals(ACTION)) {

  20. return myAidlInterface;

  21. }

  22. return null;

  23. }

相关推荐
openinstall全渠道统计19 分钟前
免填邀请码工具:赋能六大核心场景,重构App增长新模型
android·ios·harmonyos
双鱼大猫41 分钟前
一句话说透Android里面的ServiceManager的注册服务
android
双鱼大猫1 小时前
一句话说透Android里面的View的绘制流程和实现原理
android
双鱼大猫2 小时前
一句话说透Android里面的Window的内部机制
android
双鱼大猫2 小时前
一句话说透Android里面的为什么要设计Window?
android
双鱼大猫2 小时前
一句话说透Android里面的主线程创建时机,frameworks层面分析
android
苏金标3 小时前
android 快速定位当前页面
android
雾里看山6 小时前
【MySQL】内置函数
android·数据库·mysql
风浅月明6 小时前
[Android]页面间传递model列表
android
法迪6 小时前
Android自带的省电模式主要做什么呢?
android·功耗