通过 AIDL 在服务之间传递活动对象

nbe*_*_42 5 android aidl android-service android-binder

我正在尝试为不同包中的多个服务共享一个公共对象。每个服务必须调用相同的对象。

例如,服务 A(来自 APK A)实例化一个自定义对象,我希望服务 B 和 C(来自 APK B 和 C)检索该对象的引用并调用它的某些方法。

我在 Android 参考中发现使用Parcel应该是可能的:

活动对象

Parcel 的一个不同寻常的功能是能够读取和写入活动对象。对于这些对象,不写入对象的实际内容,而是写入引用该对象的特殊标记。从 Parcel 读回对象时,您不会获得该对象的新实例,而是一个对最初写入的完全相同对象进行操作的句柄。有两种形式的活动对象可用。

Binder 对象是 Android 通用跨进程通信系统的核心工具。IBinder 接口描述了一个带有 Binder 对象的抽象协议。任何这样的接口都可以写入 Parcel 中,在阅读时,您将收到实现该接口的原始对象或一个特殊的代理实现,该代理实现将回调通信回原始对象。使用的方法有 writeStrongBinder(IBinder), writeStrongInterface(IInterface), readStrongBinder(), writeBinderArray(IBinder[]), readBinderArray(IBinder[]), createBinderArray(), writeBinderList(List), readBinderList(List), createBinderArrayList() .

我试图通过 AIDL 传递我的对象(扩展绑定器)来做到这一点,但没有任何效果,当我尝试从方法 createFromParcel(Parcel in) 检索引用时,我总是得到 ClassCastException。

我的代码示例:

public class CustomObject extends Binder implements Parcelable {

  public CustomObject() {
    super();
  }

  public static final Parcelable.Creator<CustomObject> CREATOR = new Parcelable.Creator<CustomObject>() {
  public CustomObject createFromParcel(Parcel in) {
    IBinder i = in.readStrongBinder();
      // HOW TO RETRIEVE THE REFERENCE ??
      return null;
    }

    @Override
    public CustomObject[] newArray(int size) {
      return null;
    }
  };

  @Override
  public int describeContents() {
    return 0;
  }

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    dest.writeStrongBinder(this);
  }
}
Run Code Online (Sandbox Code Playgroud)

有人已经这样做了吗?

提前致谢 !

Adr*_*lor 2

这里有两种方法。

简单:对对象本身使用aidl

  • 看来您有一个现有的 AIDL 接口,您可以通过该接口将此“自定义对象”作为包裹传递。不要那样做。反而:
  • 您传递的对象本身应该由 AIDL 描述。比如说,你称它为ICustomObject.aidl
  • 在这种情况下,您不需要使对象可打包。您可能甚至不需要编写上面的代码;只需在另一种类型中使用一种 AIDL 描述的类型即可。例如,将如下行添加到服务 A 的主 AIDL 中:

    ICustomObject getCustomObject();
    
    Run Code Online (Sandbox Code Playgroud)
  • 在服务 A 中,在Stub您已有的类中,您只需返回继承自ICustomObject.

  • 在服务 B 和 C 中,您可以简单地调用该方法来获取ICustomObject. 简单的!没有包裹,没有readStrongBinder(),什么都没有。

更难

如果执行上述操作,Android 工具链会生成编组和解组对象的 Java 代码。您可以自己编写代码。

ICustomObject myObjectWhichActuallyLivesInAnotherProcess = ICustomObject.Stub.asInterface(parcel.readStrongBinder())
Run Code Online (Sandbox Code Playgroud)

甚至

ICustomObject myObjectWhichActuallyLivesInAnotherProcess = (ICustomObject)parcel.readStrongBinder().queryLocalInterface("com.your.custom.object");
Run Code Online (Sandbox Code Playgroud)

但我认为,如果你让一切都变得有帮助,你的生活会更加理智。

课堂分享注意事项

您可能想要创建一个包含ICustomObject.aidl其中内容的 Android“库项目”,以便您可以在构建 A、B 和 C 的项目之间共享生成的类。