android AIDL界面、包裹和向后兼容性
我们向第三方开发人员公开AIDL服务。我们希望从此服务返回包裹对象,但我们担心向后兼容性。我的意思是,根据parcelable的版本N编译的客户端和根据版本N+1编译的服务必须协同工作 从我的测试中,对于简单的平面对象(仅限于简单类型字段),向后兼容是可能的,只要新字段被打包在流的末尾。。。e、 gandroid 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
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
}