android AIDL 接口、parcelables 和向后兼容性

Jef*_*man 5 android ipc parcelable aidl

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

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

in.writeInt(field1);
in.writeInt(field2); // new field
Run Code Online (Sandbox Code Playgroud)

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

class D implements Parcelable {
  int field1;
}

class C implements Parcelable {
  List<D> ds;
}
Run Code Online (Sandbox Code Playgroud)

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

class D implements Parcelable {
  int field1;
  int field2; // new field
}
Run Code Online (Sandbox Code Playgroud)

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

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

这让我们不得不使用一些更宽容的格式(例如 JSON)来传递 IPC 数据。

有什么建议么?

Com*_*are 5

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

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

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

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

任何一个:

  • 第一次就做对,这样您就不会拥有“经常变化”的公共 API,或者

  • 使用 aBundle表示“经常变化”的方面,因为Bundle它是稳定的(例如, aPerson具有properties Bundle表示您希望在每隔几年主要 API 修订之间将其添加到公共 API 上的内容),或者

  • Bundle首先使用 a ,这样你的 API 就可以更多地传递属性包,或者

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

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

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

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