android AIDL界面、包裹和向后兼容性

android AIDL界面、包裹和向后兼容性,android,ipc,parcelable,aidl,Android,Ipc,Parcelable,Aidl,我们向第三方开发人员公开AIDL服务。我们希望从此服务返回包裹对象,但我们担心向后兼容性。我的意思是,根据parcelable的版本N编译的客户端和根据版本N+1编译的服务必须协同工作 从我的测试中,对于简单的平面对象(仅限于简单类型字段),向后兼容是可能的,只要新字段被打包在流的末尾。。。e、 g in.writeInt(field1); in.writeInt(field2); // new field 然而,当涉及到复杂的对象时,事情就会爆炸。比如说, class D implement

我们向第三方开发人员公开AIDL服务。我们希望从此服务返回包裹对象,但我们担心向后兼容性。我的意思是,根据parcelable的版本N编译的客户端和根据版本N+1编译的服务必须协同工作

从我的测试中,对于简单的平面对象(仅限于简单类型字段),向后兼容是可能的,只要新字段被打包在流的末尾。。。e、 g

in.writeInt(field1);
in.writeInt(field2); // new field
然而,当涉及到复杂的对象时,事情就会爆炸。比如说,

class D implements Parcelable {
  int field1;
}

class C implements Parcelable {
  List<D> ds;
}
C
s的解组失败(我尝试使用
Parcel.writeList()
Parcel.writeParcelableArray()

这件案子无法处理,这几乎是不可想象的。当然,我们可以保留旧的绑定器接口,并创建一个新的绑定器接口,该接口返回带有附加字段的新类的对象,但对于返回经常更改的类的服务,这将导致复杂的混乱。例如,interface 1.0返回一个
。现在我们添加了一个字段,我们有了一个新的binder接口2.0,它返回
Person2
对象,依此类推

这使得我们可以使用一些更宽容的格式,比如JSON,来传递IPC数据

有什么建议吗?
谢谢。

根据
Parcelable
的N版编译的客户端和AIDL接口将需要
服务的支持,直到宇宙的热死,而不仅仅是N+1,除非你想破坏一堆客户端或迫使这些开发人员更新他们的应用程序

当然,我们可以保留旧的活页夹界面


对AIDL本身的任何更改都意味着您需要新协议版本的新服务端点,更不用说对
Parcelable
定义的更改了

例如,接口1.0返回一个人。现在我们添加了一个字段,我们有了一个新的binder接口2.0,它返回Person2对象,依此类推

要么:

  • 第一次就把它做好,这样你就不会有一个“经常变化的”公共API,或者

  • 对于“经常变化的”方面,使用
    捆绑包
    ,因为
    捆绑包
    是稳定的(例如,
    拥有
    属性
    捆绑包
    ,你希望在每隔几年的重大API修订之间将其添加到公共API中),或者

  • 首先使用
    捆绑包
    ,这样您的API就更容易传递属性包,或者

  • 切换到
    Serializable
    ,尽管它可能会慢一点,因为它有版本控制的概念,或者

  • 完全转储绑定模式并使用命令模式,并使用额外的作为属性包

您的JSON替代方案大致类似于首先使用
捆绑包
,只是您不必为自己的
捆绑包
封送/解封代码而大惊小怪

Parcelable
由于速度原因专门避免版本控制。这就是为什么
Parceable
不是为持久存储而设计的,因为在保存数据和读入数据之间,类可能会发生变化。

如果您只是在AIDL中添加一个附加方法(而不是修改现有方法),您可以将附加方法作为AIDL文件中的最后一个方法,这不会破坏现有的依赖应用程序(它们仍然是根据您以前的AIDL定义构建的)。
您的新服务应用程序(使用添加的方法)将适用于旧应用程序和新应用程序(根据新的AIDL定义构建)。在新的应用程序中,如果他们正在与支持旧AIDL定义的旧版本的服务通信,他们只需要捕获IllegalArgumentException。在我的例子中,我提供了一个客户端类,它包装IPC调用,这样应用程序就不会真正进行调用,我在那里执行异常捕获,只记录情况并从该方法返回null。

现在Android 10到中支持AIDL的版本控制

“对AIDL本身的任何更改都意味着您需要新协议版本的新服务端点”-是否可以根据意图中的数据从
onBind()
返回不同的存根impl?然后新的绑定器可以返回不同的可打包impl。@JeffreyBlattman:根据意图中的数据,是否可以从onBind()返回不同的存根impl?“--是的,但这仍然意味着不同的
.Stub
,因此现在您有了
.Stub
.Stub2
,以及
.Stub3
等等。瞧,这让人想起你对
包裹问题的抱怨。正确的做法是按照建议使用
包裹。换句话说,将所有字段塞入一个
,然后只写/读
。这似乎只是针对平台代码,而不是应用程序。它是否在developer.android.com(与source.android.com相反)的任何地方引用?
class D implements Parcelable {
  int field1;
  int field2; // new field
}