Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android enum: set enum programatically from integer value

I want to serialized/deserialize a java enum as an int. I'm using the Android Wear Wearable Data Layer API to transport an enum setting between Wear and Phone devices. This means I need to convert my enum to an int and back to an enum programatically. Note that I do NOT need to create new enums, only match an existing one. My concern is that although I can easily set a value using an enum method, it seems that I could easily set a non-existing value.

public enum Color {
    Undefined (0), Red(1), Yellow(2), Blue(3), Green(4), Black(5);
    private int mValue;
    private Color(int value) { this.mValue = value;} // Constructor
    public int id(){return mValue;}                  // Return enum index
    public void setValue(int i){mValue = i;};        // Set index
}

Thus, I can do the following:

Color color = Color.Red;
int   index = color.id();
putDataMapReq.getDataMap().putInt("color",index);          

This value can be transported as an int, and I would like to reconstitute it as follows but I can't get the setValue() method to be accessible:

int newindex = dataMap.getInt ("color");
Color newColor = Color.Undefined;
newColor.setValue(newIndex);

What is this the right way to do this? Is there a way to validate that the new index value is legitimate?

like image 208
Hephaestus Avatar asked Aug 04 '16 03:08

Hephaestus


2 Answers

I recommend you to use emen's method name and valueof for simplicity.

your Color will be like this:

public enum Color {
    Undefined , Red, Yellow, Blue, Green, Black;
}

Serialize:

Color color = Color.Red;
String name = color.name();

Deserialize:

String newName = dataMap.getString("color");
Color newColor = Color.valueOf(newName);

UPDATE

If you want to use integer, your code will be like below:

public enum Color {
    Undefined (0), Red(1), Yellow(2), Blue(3), Green(4), Black(5);
    private int mValue;
    Color(int value) { this.mValue = value;} // Constructor
    public int id(){return mValue;}                  // Return enum index

    public static Color fromId(int value) {
        for(Color color : values()) {
            if (color.mValue == value) {
                return color;
            }
        }
        return Undefined;
    }
}

Serialize:

    Color color = Color.Red;
    int index = color.id();

Deserialize:

    int newIndex = dataMap.getInt("color");
    Color newColor = Color.fromId(newIndex);
like image 73
nshmura Avatar answered Nov 15 '22 04:11

nshmura


First, I'd highly suggest that your enums be made immutable to prevent surprising their users. The original use of enums as stated in Java 1.5 documentation is to replace lists of constants.

As for transferring data, the Android Wearable docs on data syncing suggest using a DataMap whenever possible:

When possible, use the DataMap class. This approach lets you work with data items in the form of an Android Bundle, so the system does object serialization and deserialization for you, and you can manipulate data with key-value pairs.

While I don't have experience with wearables, Android has its own serialization mechanism with Bundle and Parcelable, and there are projects like Parceler that will help generate the serialization code for you. You can convert bundles into a DataMap using #fromBundle(...).

If you go the Parceler route, you can either rely on the built-in enum serialization or write arbitrary code. It's a frequent Java pattern to create an enum instance from some canonical value by looking through available values for a match (or looking them up in a pre-computed map if very large):

public enum Foo {
  VAL_1("bar");
  private final String strval;
  Foo(final String strval) { this.strval = strval; }

  public static Foo fromStrval(final String strval) {
    for (final Foo f : Foo.values()) {
      if (f.strval.equals(strval)) return f;
    }

    return null;
  }
}
like image 25
Del Avatar answered Nov 15 '22 05:11

Del