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

时间:2013-05-27 07:01:17

标签: android android-service aidl android-binder

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

例如,服务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);
  }
}

有人已经这样做了吗?

提前致谢!

3 个答案:

答案 0 :(得分:2)

以下是两种方法。

简单:对象本身使用aidl

  • 您似乎有一个现有的AIDL界面,您可以通过该界面将此“自定义对象”作为宗地传递。不要那样做。代替:
  • 您传递的对象本身应由AIDL描述。比如说,你称之为ICustomObject.aidl
  • 在这种情况下,你需要使对象Parcelable。你可能甚至不需要编写上面的代码;只需在另一个中使用一种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");

但是,如果你把所有事情都做好了,我认为你的生活会更加健全。

关于课堂分享的说明

您可能想要创建一个Android“库项目”,其中包含ICustomObject.aidl,这样您就可以在构建A,B和C的项目之间共享结果类。

答案 1 :(得分:0)

你看过content providers吗?

答案 2 :(得分:0)

在对自己进行相当广泛的调查后,我认为实际上并没有这样做。您获得的ClassCastException是将BinderProxy(这是一个扩展IBinder的私有类)强制转换为实际类(CustomObject)的结果。当引用其他进程中的Binders时,似乎总是传递BinderProxy,这是当它们声明“实现该接口的原始对象或特殊代理实现”时它们所引用的对象。 BinderProxy允许您调用IBinderonTransact()方法,但没有其他方法。

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