【问题标题】:Pass active objects between services through AIDL通过 AIDL 在服务之间传递活动对象
【发布时间】:2013-05-21 23:58:54
【问题描述】:

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

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

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

活动对象

Parcel 的一个不同寻常的功能是能够主动读写 对象。对于这些对象,对象的实际内容不是 写入,而是写入引用对象的特殊标记。 从包裹中读取对象时,您不会得到新的 对象的实例,而是一个对确切的操作的句柄 与最初编写的对象相同。有两种形式的活动 可用的对象。

Binder 对象是 Android 通用跨进程的核心工具 通讯系统。 IBinder 接口描述了一个抽象 带有Binder对象的协议。任何这样的接口都可以写入 一个包裹,阅读后您将收到原始物品 实现该接口或特殊的代理实现 将调用传递回原始对象。使用的方法是 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);
  }
}

有人已经这样做了吗?

提前致谢!

【问题讨论】:

  • 你有没有想过如何做到这一点?几年前我尝试过并放弃了。现在我再次尝试解决与您相同的问题/结果。
  • 不幸的是,没有。对于这个项目,我更改了我的流程,以便在每次我想调用对象上的方法时检索对象的副本。不完美,但它正在工作。但我仍然很想知道这个问题是否有解决方案

标签: android android-service aidl android-binder


【解决方案1】:

这里有两种方法。

简单:对对象本身使用aidl

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

    ICustomObject getCustomObject();
    
  • 在服务 A 中,在您已经拥有的 Stub 类中,您只需返回从 ICustomObject 继承的内容。

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

更难

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

ICustomObject myObjectWhichActuallyLivesInAnotherProcess = ICustomObject.Stub.asInterface(parcel.readStrongBinder())

甚至

ICustomObject myObjectWhichActuallyLivesInAnotherProcess = (ICustomObject)parcel.readStrongBinder().queryLocalInterface("com.your.custom.object");

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

关于课堂分享的注意事项

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

【讨论】:

    【解决方案2】:

    你看过content providers吗?

    【讨论】:

    • 我不想只分享数据。为此,一个简单的 AIDL 机制就足够了。我需要的是共享一个复杂的对象,该对象必须是所有服务都可以调用的一些方法唯一的。
    【解决方案3】:

    在我自己对此进行了相当广泛的研究之后,我认为它实际上无法完成。您得到的 ClassCastException 是将 BinderProxy(这是一个扩展 IBinder 的私有类)转换为您的实际类 (CustomObject) 的结果。 BinderProxy 在跨其他进程引用 Binders 时似乎总是被传递,这是他们在声明“实现该接口的原始对象或特殊代理实现”时引用的对象。 BinderProxy 确实允许您调用 IBinderonTransact() 方法,但仅此而已。

    老实说,当他们声明“原始对象”跨进程传递时,我真的认为文​​档是不正确的,因为该类的文档还有几个其他实例是 both blatantly copy-pasted and wrong

    【讨论】:

      猜你喜欢
      • 2015-03-05
      • 2014-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-28
      • 2023-03-23
      • 2013-06-11
      • 1970-01-01
      相关资源
      最近更新 更多