【问题标题】:Mirror class from existing library and implement Parcelable从现有库中镜像类并实现 Parcelable
【发布时间】:2015-09-17 00:16:43
【问题描述】:

镜像类和实现 Parcelable 的最佳方法是什么?

这是因为我使用了一个库,但我还需要广播一个对象,为了做到这一点,我需要在不编辑库中的原始类的情况下实现 Parcelable?

更新:

  • 该库是开源的,但它是用纯 Java 编写的。
  • 我不希望在提交此 repo 时对其自身的类进行更改,并希望保持库纯 java。
  • 该库是 pires 的 OBD2 java 库。
  • 类是 OBDCommand.java

【问题讨论】:

    标签: android class


    【解决方案1】:

    编辑: 所以我查看了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 实现,使用反射读取对象字段值并将它们写入ParcelParcelable.Creator 工厂可以使用Class.newInstance() 重新创建对象并使用反射写入值从Parcel 到新对象。缺点:将库更新到新版本可能会破坏您的 Parcelable 代码。但是,如果您必须反序列化使用早期版本存储的任何对象,至少有可能从 Parcel 读取旧版本的值并将它们写入新版本,解决您没有的问题的值。

    • 这不是开源的,但是你要镜像的类实现了Serializable

      您可以将对象序列化为ByteArrayOutputStream,然后将字节写入Parcel。然后Parcelable.Creator 工厂将读取字节并创建一个ByteArrayInputStream,可以从中反序列化对象。缺点:如果您的 Parcel 存储在某个位置(例如数据库中),并且库已更新为新版本,则如果该类未处理旧版本的反序列化,则尝试反序列化存储的对象将失败。

    • 以上都不是?

      您可以反编译和 grok 类,然后像使用开源策略一样使用反射来读取和写入字段值。缺点:你必须反编译和学习类。每次发布新库时,您都必须这样做以检查是否有任何更改。

    如果您想要更详细的答案,请在您的问题中添加更多详细信息:哪个类、哪个库、它会定期修订等等。

    【讨论】:

    • 感谢您的回复。我已经更新了我的问题
    • 更新了我的答案。 OBDCommand 类需要添加一些您的Parcelable 类可以使用的序列化方法。
    • 非常感谢您的时间和帮助。我将不得不考虑您的建议
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多