【问题标题】:android AIDL interface, parcelables and backwards compatibilityandroid AIDL 接口、parcelables 和向后兼容性
【发布时间】:2013-08-12 22:35:30
【问题描述】:

我们向第三方开发者公开 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;
}

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

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

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

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

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

有什么建议吗?

【问题讨论】:

    标签: android ipc parcelable aidl


    【解决方案1】:

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

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

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

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

    要么:

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

    • 使用Bundle 表示“经常变化”的方面,因为Bundle 是稳定的(例如,Person 有一个properties Bundle 用于您希望在公众上发布的内容API 在每隔几年的主要 API 修订之间),或

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

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

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

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

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

    【讨论】:

    • “对 AIDL 本身的任何更改都意味着您需要新协议版本的新服务端点”- 是否可以根据中的数据从 onBind() 返回不同的 Stub impl意图?那么新的 binder 可以返回不同的 parcelable impls。
    • @JeffreyBlattman:“根据意图中的数据,是否可以从 onBind() 返回不同的 Stub impl?” -- 是的,但这仍然意味着不同的.Stub,所以现在你有了.Stub.Stub2,还有.Stub3 等等。 IOW,这让人想起你对Parcelable 问题的抱怨。
    • 这里正确的做法是按照建议使用Bundle 包裹。换句话说,将你所有的字段塞进Bundle,然后只写/读Bundle
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 似乎这只是针对平台代码,而不是应用程序。它是否在 developer.android.com(而不是 source.android.com)的任何地方引用?
      猜你喜欢
      • 2021-07-13
      • 1970-01-01
      • 1970-01-01
      • 2019-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 2011-02-06
      相关资源
      最近更新 更多