【问题标题】:How to read and write Enum into parcel on Android?如何在 Android 上将 Enum 读写到 parcel 中?
【发布时间】:2016-07-03 22:44:03
【问题描述】:

这是我的模型类:

public enum Action {
    RETRY, SETTINGS
}

private int imageId;
private String description;
private String actionName;
private Action action;

public NetworkError(int imageId, String description, String actionName, Action action ) {
    this.imageId = imageId;
    this.description = description;
    this.actionName = actionName;
    this.action = action;
}

public int getImageId() {
    return imageId;
}

public void setImageId(int imageId) {
    this.imageId = imageId;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}

public String getActionName() {
    return actionName;
}

public void setActionName(String actionName) {
    this.actionName = actionName;
}


@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeInt(this.imageId);
    dest.writeString(this.description);
    dest.writeString(this.actionName);
}

protected NetworkError(Parcel in) {
    this.imageId = in.readInt();
    this.description = in.readString();
    this.actionName = in.readString();
}

public static final Parcelable.Creator<NetworkError> CREATOR = new Parcelable.Creator<NetworkError>() {
    @Override
    public NetworkError createFromParcel(Parcel source) {
        return new NetworkError(source);
    }

    @Override
    public NetworkError[] newArray(int size) {
        return new NetworkError[size];
    }
};

【问题讨论】:

标签: android enums parcelable parcel


【解决方案1】:

我有类似的问题,我的解决方案是:

parcel.writeString(this.questionType.name());

阅读:

this.questionType = QuestionType.valueOf(parcel.readString());

QuestionType 是枚举,记住元素的顺序很重要。

【讨论】:

  • 完美答案:)
【解决方案2】:

最高效 - 内存效率最高的 - 捆绑包是通过使用 ENUM 序数值创建的。

写信给包裹dest.writeInt(enum_variable.ordinal());

读取包裹enum_variable = EnumName.values()[in.readInt()];

这应该没问题,除非您不注意文档的警告:

Parcel 不是通用的序列化机制。此类(以及用于将任意对象放入 Parcel 的相应 Parcelable API)被设计为高性能 IPC 传输。因此,将任何 Parcel 数据放入持久存储是不合适的:Parcel 中任何数据的底层实现发生变化都可能导致旧数据不可读。

换句话说,您不应该在代码版本之间传递 Parcel,因为它可能不起作用。

【讨论】:

  • 我已经可以看到人们积极支持string 答案而不是这个ordinal 答案,因为通常你总是不鼓励使用.ordinal(),但考虑到你提到的警告,这是可接受的用例之一
  • 是的,您必须了解包裹的限制。个人尝试尽可能多地使用 Protobufs,因为它们在 golang、kotlin、java、dart 等中工作。这意味着我不必处理打包和解包相同数据的几种不同方式。 (仍然没有为此做出“正确答案”......)
【解决方案3】:

任何enum 都是可序列化的。

您可以在writeToParcel()dest.writeSerializable(action) 中执行此操作

在构造函数中:action = (Action) in.readSerializable()

【讨论】:

  • 这是最容易实现的解决方案,但考虑到serializable 接口比parcelable 慢得多,我想知道与下面您投enum 的答案相比,这是否对性能有任何影响到更原始的类型。
【解决方案4】:

枚举声明:

public enum Action {

    NEXT(1),
    OK(2);

    private int action;

    Action(int action) {
        this.action = action;
    }

}

从包裹中读取:

protected ActionParcel(Parcel in) {
    int actionTmp = in.readInt();
    action = Tutorials.Action.values()[actionTmp];
}

写信到包裹:

public void writeToParcel(Parcel dest, int flags) {
    int actionTmp = action == null ? -1 : action.ordinal();
    dest.writeInt(actionTmp);
}

【讨论】:

  • 不知道为什么其他方法会抛出异常。这种方法对我有用。
【解决方案5】:

示例 Kotlin 代码(空安全):

writeInt(action?.ordinal ?: -1)

action = readInt().let { if (it >= 0) enumValues<MyEnum>()[it] else null }

可以封装在一个 write/readEnum 方法中作为 Parcel 的扩展:

fun <T : Enum<T>> Parcel.writeEnum(value: T?) = 
    writeInt(value?.ordinal ?: -1)

inline fun <reified T : Enum<T>> Parcel.readEnum(): T? = 
    readInt().let { if (it >= 0) enumValues<T>()[it] else null }

【讨论】:

    【解决方案6】:

    这样做的一种方法是以整数形式编写动作,并将它们正确地读取为整数,然后将它们转换为动作。我的意思:

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.imageId);
        dest.writeString(this.description);
        dest.writeString(this.actionName);
    
        int actionAsInt = action == Action.RETRY ? 1 : 0;
        dest.writeInt(actionAsInt);
    }
    
    protected NetworkError(Parcel in) {
        this.imageId = in.readInt();
        this.description = in.readString();
        this.actionName = in.readString();
    
        int actionAsInt = in.readInt();
        this.action = actionAsInt == 1 ? Action.RETRY : Action.SETTINGS;
    }
    

    试试看。成功...

    【讨论】:

      【解决方案7】:

      现在,您可以使用 Kotlin Parcelize 编写类似的内容:

      import android.os.Parcelable
      import kotlinx.parcelize.Parcelize
      
      @Parcelize
      class NetworkError(
          var imageId: Int,
          var description: String,
          var actionName: String,
          private val action: Action
      ): Parcelable {
      
          @Parcelize
          enum class Action: Parcelable {
              RETRY, SETTINGS
          }
      }
      

      【讨论】:

        【解决方案8】:

        读取包裹

        action = Nav.valueOf(in.readString());
        

        写包裹

        out.writeString(action.name());
        

        【讨论】:

          【解决方案9】:

          你有没有这样尝试过

          @Parcelize enum class State {
              ON, OFF
          }
          
          @Parcelize
          class PowerSwitch(var state: State) : Parcelable
          

          让我知道它是否适合你?

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-09-18
            • 1970-01-01
            • 1970-01-01
            • 2011-02-13
            • 2015-05-06
            • 1970-01-01
            • 2020-01-04
            相关资源
            最近更新 更多