4

我们向第三方开发者公开 AIDL 服务。我们希望从该服务返回可打包的对象,但我们担心向后兼容性。我的意思是,客户端针对 Parcelable 的版本 N 编译,并且针对版本 N+1 编译的服务必须协同工作。

根据我的测试,对于简单的平面对象(仅限简单类型字段),只要在流的末尾打包新字段......例如,向后兼容是可能的,

in.writeInt(field1);
in.writeInt(field2); // new field

然而,当涉及到复杂的对象时,事情就会爆炸。例如,

class D implements Parcelable {
  int field1;
}

class C implements Parcelable {
  List<D> ds;
}

如果将第二个字段添加到 class D

class D implements Parcelable {
  int field1;
  int field2; // new field
}

类的解组C失败(我尝试使用Parcel.writeList()and Parcel.writeParcelableArray())。

这似乎几乎不可思议,这起案件无法处理。当然,我们可以保留旧的 binder 接口,并创建一个新的 binder 接口,该接口返回带有附加字段的新类的对象,但是对于返回经常更改的类的服务,这将导致混乱的混乱。例如,接口 1.0 返回一个Person. 现在我们添加一个字段,我们有一个新的 binder 接口 2.0,它返回Person2对象,等等。

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

有什么建议么?

4

3 回答 3

3

针对版本 NParcelable和 AIDL 接口编译的客户端将需要得到支持,Service直到宇宙热死,而不仅仅是直到 N+1,除非你想破坏一堆客户端或有能力强迫那些开发人员更新他们的应用程序。

当然,我们可以保留旧的 binder 界面原样

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

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

任何一个:

  • 第一次就做好,这样您就没有“经常变化”的公共 API,或者

  • 将 aBundle用于“经常变化”的方面,因为Bundle它是稳定的(例如,aPerson有一个properties Bundle你希望在每隔几年的主要 API 修订之间使用公共 API 的东西),或者

  • 首先使用 a Bundle,因此您的 API 更多地传递属性包,或者

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

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

您的 JSON 替代方案大致类似于首先使用 a Bundle,除了您不必为自己的编组/解编组代码大惊小怪 a Bundle

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

于 2013-08-13T00:07:45.363 回答
0

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

于 2016-02-25T17:48:39.450 回答
0

Android 10 现在通过Stable AIDL支持 AIDL 的版本控制。

于 2020-02-27T09:14:35.620 回答