Как читать и записывать Enum в посылку на Android?

Вот мой модельный класс:

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];
    }
};

person Figen Güngör    schedule 03.07.2016    source источник
comment
Перечисления Serializable.   -  person CommonsWare    schedule 04.07.2016
comment
parcelabler.com   -  person tachyonflux    schedule 04.07.2016
comment
ты пробовал dest.writeValue()   -  person EpicPandaForce    schedule 15.09.2016


Ответы (6)


У меня была аналогичная проблема, и мое решение было:

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

и для чтения:

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

QuestionType - это перечисление, и помните, что порядок элементов имеет значение.

person milosnkb    schedule 07.09.2016
comment
Идеальный ответ :) - person Neo; 25.04.2020

Наиболее эффективный пакет с эффективным использованием памяти создается с использованием порядкового значения ENUM.

Запись в посылку dest.writeInt(enum_variable.ordinal());

Чтение из посылки enum_variable = EnumName.values()[in.readInt()];

Это должно быть хорошо, если вы не прислушиваетесь к советам документации:

Parcel не является универсальным механизмом сериализации. Этот класс (и соответствующий Parcelable API для размещения произвольных объектов в Parcel) разработан как высокопроизводительный IPC-транспорт. Таким образом, нецелесообразно помещать какие-либо данные Parcel в постоянное хранилище: изменения в базовой реализации любых данных в Parcel могут сделать старые данные нечитаемыми.

Другими словами, вы не должны передавать Parcels между версиями кода, потому что это может не сработать.

person Brendon Whateley    schedule 31.01.2018
comment
Я уже вижу, как люди агрессивно голосуют за ответ string вместо этого ответа ordinal, потому что обычно вам всегда не рекомендуется использовать .ordinal(), но, учитывая упомянутое вами предостережение, это один из приемлемых вариантов использования. - person avalancha; 23.01.2020
comment
Да, вы должны знать об ограничениях посылок. Лично я стараюсь использовать Protobuf как можно чаще, потому что они работают в golang, kotlin, java, dart и т. д. Это означает, что мне не приходится иметь дело с несколькими различными способами упаковки и распаковки одних и тех же данных. (До сих пор нет правильного ответа для этого...) - person Brendon Whateley; 24.01.2020

Любой enum сериализуем.

Вы можете сделать это в writeToParcel(): dest.writeSerializable(action)

И в конструкторе: action = (Action) in.readSerializable()

person Geekarist    schedule 27.10.2017
comment
Это самое простое решение для реализации, но, учитывая, что интерфейс serializable намного медленнее, чем parcelable, мне интересно, влияет ли это на производительность по сравнению с ответами ниже, где вы приводите enum к более примитивному типу. - person mcy; 22.11.2017

Деклерация перечисления:

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);
}
person Jagadeesh    schedule 15.09.2016
comment
Не знаю, почему другие методы вызывали исключения. Этот метод работал для меня. - person Dushyant Suthar; 06.12.2019

Пример кода 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 }
person Benjamin Mesing    schedule 02.01.2020

Один из способов сделать это — записать действия в виде целых чисел, правильно прочитать их как целые числа и преобразовать их в действия. Что я имею в виду:

@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;
}

Попытайся. Успех ...

person Ahmed Matem Ahmed    schedule 10.10.2018