How to read and write Enum into parcel on Android?
Asked Answered
L

10

77

Here is my model class:

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];
    }
};
Lazybones answered 3/7, 2016 at 22:44 Comment(3)
Enums are Serializable.Kalb
parcelabler.comJacksmelt
have you tried dest.writeValue()Doerrer
C
89

I had similar problem and my solution was:

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

and for reading :

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

QuestionType is enum and remember that ordering of elements matters.

Catacaustic answered 7/9, 2016 at 8:26 Comment(1)
Perfect Answer :)Draghound
H
50

The most efficient - memory efficient - bundle is created by using the ENUM ordinal value.

Writing to Parcel dest.writeInt(enum_variable.ordinal());

Reading from parcel enum_variable = EnumName.values()[in.readInt()];

This should be fine unless you don't heed the documentation's admonitions:

Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.

In other words, you shouldn't pass Parcels between code versions because it may not work.

Harriman answered 31/1, 2018 at 2:8 Comment(2)
I can already see the people aggressively upvoting the string answer over this ordinal answer, because normally you're always discouraged from using .ordinal(), but given the caveat you mentioned, this is one of the acceptable use casesLexis
Yes, you have to be aware of the restrictions of Parcels. Personally try to use Protobufs as much as possible because they work in golang, kotlin, java, dart, etc. This means I don't have to deal with several different ways of packing and unpacking the same data. (Still no "Correct Answer" maked for this...)Harriman
T
35

Any enum is serializable.

You can do this in writeToParcel(): dest.writeSerializable(action)

And in the constructor: action = (Action) in.readSerializable()

Toggle answered 27/10, 2017 at 15:46 Comment(1)
This is the easiest solution to implement but considering serializable interface is much slower than parcelable, I wonder if this has any effect on performance compared to the answers below where you cast the enum to a more primitive type.Hildegardhildegarde
A
6

Now, you can write something like this using 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
    }
}
Ambrosio answered 20/9, 2021 at 14:22 Comment(0)
J
5

Enum decleration:

public enum Action {

    NEXT(1),
    OK(2);

    private int action;

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

}

Reading from Parcel:

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

Writing to parcel:

public void writeToParcel(Parcel dest, int flags) {
    int actionTmp = action == null ? -1 : action.ordinal();
    dest.writeInt(actionTmp);
}
Jessi answered 15/9, 2016 at 10:58 Comment(1)
Don't know why other methods were throwing exceptions. This method worked for me.Johathan
P
3

Sample Kotlin-Code (null-safe):

writeInt(action?.ordinal ?: -1)

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

Which can be encapsulated in a write/readEnum Methods as extensions to 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 }
Puckett answered 2/1, 2020 at 12:23 Comment(0)
D
2

One way to do this is to write Actions in integer and read them properly as integer and convert them into Action. What I mean:

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

Try it. Success ...

Dejesus answered 10/10, 2018 at 19:41 Comment(0)
U
1

Read parcel

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

Write parcel

out.writeString(action.name());
Ulrikeulster answered 16/8, 2021 at 5:59 Comment(0)
J
0

Have you tried like this

@Parcelize enum class State {
    ON, OFF
}

@Parcelize
class PowerSwitch(var state: State) : Parcelable

Let me know it work for you or not?

Julianjuliana answered 9/12, 2021 at 14:42 Comment(0)
H
0

Using the fact that enums are serializeable

My enum:

public enum HouseEnum {
    GRYFFINDOR, HUFFLEPUFF, RAVENCLAW, SLYTHERIN
}

When placing in bundle:

args.putSerializable(HOUSE, houseEnum);

When retrieving from bundle:

houseEnum = (HouseEnum) getArguments().getSerializable(HOUSE);
Homiletic answered 19/4, 2022 at 21:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.