【发布时间】:2015-09-17 00:16:43
【问题描述】:
镜像类和实现 Parcelable 的最佳方法是什么?
这是因为我使用了一个库,但我还需要广播一个对象,为了做到这一点,我需要在不编辑库中的原始类的情况下实现 Parcelable?
更新:
- 该库是开源的,但它是用纯 Java 编写的。
- 我不希望在提交此 repo 时对其自身的类进行更改,并希望保持库纯 java。
- 该库是 pires 的 OBD2 java 库。
- 类是 OBDCommand.java
【问题讨论】:
镜像类和实现 Parcelable 的最佳方法是什么?
这是因为我使用了一个库,但我还需要广播一个对象,为了做到这一点,我需要在不编辑库中的原始类的情况下实现 Parcelable?
更新:
【问题讨论】:
编辑:
所以我查看了pires/obd-java-api on GitHub,现在我看到了你的问题:OBDCommand 类是一个抽象类,它有四个抽象子类和四十三个 具体子类。
哎呀。
使用反射为所有这些类创建Parcel 工厂并不是我想做的事情。所以我认为你最好的选择是:
与 Paulo Pires 谈谈如何让 OBDCommand 实现 Serializable。一旦OBDCommand 实现Serializable,就应该有人遍历所有子类,确保所有字段都可以序列化,并且所有临时字段都标记为transient。
那么你可以有一个这样的类:
public class ParcelableOBDCommand implements Parcelable {
private OBDCommand mObdCommand;
public ParcelableOBDCommand(OBDCommand obdCommand) {
mObdCommand = obdCommand;
}
public OBDCommand getObdCommand() {
return mObdCommand;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(mObdCommand);
dest.writeInt(baos.toByteArray().length);
dest.writeByteArray(baos.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public static final Parcelable.Creator<ParcelableOBDCommand> CREATOR = new Parcelable.Creator<ParcelableOBDCommand>() {
@Override
public ParcelableOBDCommand createFromParcel(Parcel source) {
try {
byte[] bytesIn = new byte[source.readInt()];
source.readByteArray(bytesIn);
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytesIn));
return new ParcelableOBDCommand((OBDCommand) in.readObject());
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@Override
public ParcelableOBDCommand[] newArray(int size) {
return new ParcelableOBDCommand[size];
}
};
}
请注意,这仅在 OBDCommand 实现 Serializable 时有效。
还要注意Parcelable 的全部目的是摆脱Serializable 的反射开销,所以我们在这里有点违背了整个目的。 “OBD 命令”实际上只是几个字节,所以 Paulo 可能对如何序列化这个类家族有更好的想法。另外,这取决于您在广播服务中使用类的方式,也许您不需要将所有内容保存在Parcel 中以进行服务广播。但策略是:在OBDCommand 级别实现(纯Java,非Android)读取/写入OBDCommand 子类的方法,然后编写一个使用底层纯Java 机制的Parcelable 类。
这是一个您可以访问源代码的开源库吗?
您可以创建一个Parcelable 实现,使用反射读取对象字段值并将它们写入Parcel,Parcelable.Creator 工厂可以使用Class.newInstance() 重新创建对象并使用反射写入值从Parcel 到新对象。缺点:将库更新到新版本可能会破坏您的 Parcelable 代码。但是,如果您必须反序列化使用早期版本存储的任何对象,至少有可能从 Parcel 读取旧版本的值并将它们写入新版本,解决您没有的问题的值。
这不是开源的,但是你要镜像的类实现了Serializable?
您可以将对象序列化为ByteArrayOutputStream,然后将字节写入Parcel。然后Parcelable.Creator 工厂将读取字节并创建一个ByteArrayInputStream,可以从中反序列化对象。缺点:如果您的 Parcel 存储在某个位置(例如数据库中),并且库已更新为新版本,则如果该类未处理旧版本的反序列化,则尝试反序列化存储的对象将失败。
以上都不是?
您可以反编译和 grok 类,然后像使用开源策略一样使用反射来读取和写入字段值。缺点:你必须反编译和学习类。每次发布新库时,您都必须这样做以检查是否有任何更改。
如果您想要更详细的答案,请在您的问题中添加更多详细信息:哪个类、哪个库、它会定期修订等等。
【讨论】:
OBDCommand 类需要添加一些您的Parcelable 类可以使用的序列化方法。