[android] Passing enum or object through an intent (the best solution)

I have an activity that when started needs access to two different ArrayLists. Both Lists are different Objects I have created myself.

Basically I need a way to pass these objects to the activity from an Intent. I can use addExtras() but this requires a Parceable compatible class. I could make my classes to be passed serializable but as I understand this slows down the program.

What are my options?

Can I pass an Enum?

As an aside: is there a way to pass parameters to an Activity Constructor from an Intent?

This question is related to android

The answer is


For passing an enum by intent, you can convert enum into integer.

Ex:

public enum Num{A ,B}

Sending(enum to integer):

Num send = Num.A;
intent.putExtra("TEST", send.ordinal());

Receiving(integer to enum):

Num rev;
int temp = intent.getIntExtra("TEST", -1);
if(temp >= 0 && temp < Num.values().length)
    rev = Num.values()[temp];

Best regards. :)


you can use enum constructor for enum to have primitive data type..

public enum DaysOfWeek {
    MONDAY(1),
    TUESDAY(2),
    WEDNESDAY(3),
    THURSDAY(4),
    FRIDAY(5),
    SATURDAY(6),
    SUNDAY(7);

    private int value;
    private DaysOfWeek(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }

    private static final SparseArray<DaysOfWeek> map = new SparseArray<DaysOfWeek>();

    static
    {
         for (DaysOfWeek daysOfWeek : DaysOfWeek.values())
              map.put(daysOfWeek.value, daysOfWeek);
    }

    public static DaysOfWeek from(int value) {
        return map.get(value);
    }
}

you can use to pass int as extras then pull it from enum using its value.


Use Kotlin Extension Functions

inline fun <reified T : Enum<T>> Intent.putExtra(enumVal: T, key: String? = T::class.qualifiedName): Intent =
    putExtra(key, enumVal.ordinal)

inline fun <reified T: Enum<T>> Intent.getEnumExtra(key: String? = T::class.qualifiedName): T? =
    getIntExtra(key, -1)
        .takeUnless { it == -1 }
        ?.let { T::class.java.enumConstants[it] }

This gives you the flexibility to pass multiple of the same enum type, or default to using the class name.

// Add to gradle
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

// Import the extension functions
import path.to.my.kotlin.script.putExtra
import path.to.my.kotlin.script.getEnumExtra

// To Send
intent.putExtra(MyEnumClass.VALUE)

// To Receive
val result = intent.getEnumExtra<MyEnumClass>()

Most of the answers that are using Parcelable concept here are in Java code. It is easier to do it in Kotlin.

Just annotate your enum class with @Parcelize and implement Parcelable interface.

@Parcelize
enum class ViewTypes : Parcelable {
TITLE, PRICES, COLORS, SIZES
}

If you just want to send an enum you can do something like:

First declare an enum containing some value(which can be passed through intent):

 public enum MyEnum {
    ENUM_ZERO(0),
    ENUM_ONE(1),
    ENUM_TWO(2),
    ENUM_THREE(3);
    private int intValue;

    MyEnum(int intValue) {
        this.intValue = intValue;
    }

    public int getIntValue() {
        return intValue;
    }

    public static MyEnum getEnumByValue(int intValue) {
        switch (intValue) {
            case 0:
                return ENUM_ZERO;
            case 1:
                return ENUM_ONE;
            case 2:
                return ENUM_TWO;
            case 3:
                return ENUM_THREE;
            default:
                return null;
        }
    }
}

Then:

  intent.putExtra("EnumValue", MyEnum.ENUM_THREE.getIntValue());

And when you want to get it:

  NotificationController.MyEnum myEnum = NotificationController.MyEnum.getEnumByValue(intent.getIntExtra("EnumValue",-1);

Piece of cake!


You can make your enum implement Parcelable which is quite easy for enums:

public enum MyEnum implements Parcelable {
    VALUE;


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

    @Override
    public void writeToParcel(final Parcel dest, final int flags) {
        dest.writeInt(ordinal());
    }

    public static final Creator<MyEnum> CREATOR = new Creator<MyEnum>() {
        @Override
        public MyEnum createFromParcel(final Parcel source) {
            return MyEnum.values()[source.readInt()];
        }

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

You can then use Intent.putExtra(String, Parcelable).

UPDATE: Please note wreckgar's comment that enum.values() allocates a new array at each call.

UPDATE: Android Studio features a live template ParcelableEnum that implements this solution. (On Windows, use Ctrl+J)


I like simple.

  • The Fred activity has two modes -- HAPPY and SAD.
  • Create a static IntentFactory that creates your Intent for you. Pass it the Mode you want.
  • The IntentFactory uses the name of the Mode class as the name of the extra.
  • The IntentFactory converts the Mode to a String using name()
  • Upon entry into onCreate use this info to convert back to a Mode.
  • You could use ordinal() and Mode.values() as well. I like strings because I can see them in the debugger.

    public class Fred extends Activity {
    
        public static enum Mode {
            HAPPY,
            SAD,
            ;
        }
    
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.betting);
            Intent intent = getIntent();
            Mode mode = Mode.valueOf(getIntent().getStringExtra(Mode.class.getName()));
            Toast.makeText(this, "mode="+mode.toString(), Toast.LENGTH_LONG).show();
        }
    
        public static Intent IntentFactory(Context context, Mode mode){
            Intent intent = new Intent();
            intent.setClass(context,Fred.class);
            intent.putExtra(Mode.class.getName(),mode.name());
    
            return intent;
        }
    }
    

You can pass an enum through as a string.

public enum CountType {
    ONE,
    TWO,
    THREE
}

private CountType count;
count = ONE;

String countString = count.name();

CountType countToo = CountType.valueOf(countString);

Given strings are supported you should be able to pass the value of the enum around with no problem.


Don't use enums. Reason #78 to not use enums. :) Use integers, which can easily be remoted through Bundle and Parcelable.


about Oderik's post:

You can make your enum implement Parcelable which is quite easy for enums:

public enum MyEnum implements Parcelable { ... } You can than use Intent.putExtra(String, Parcelable).

If you define a MyEnum variable myEnum, then do intent.putExtra("Parcelable1", myEnum), you will get a "The method putExtra(String, Parcelable) is ambiguous for the type Intent" error message. because there is also a Intent.putExtra(String, Parcelable) method, and original 'Enum' type itself implements the Serializable interface, so compiler does not know choose which method(intent.putExtra(String, Parcelable/or Serializable)).

Suggest that remove the Parcelable interface from MyEnum, and move the core code into wrap class' Parcelable implementation, like this(Father2 is a Parcelable and contain an enum field):

public class Father2 implements Parcelable {

AnotherEnum mAnotherEnum;
int mField;

public Father2(AnotherEnum myEnum, int field) {
    mAnotherEnum = myEnum;
    mField = field;
}

private Father2(Parcel in) {
    mField = in.readInt();
    mAnotherEnum = AnotherEnum.values()[in.readInt()];
}

public static final Parcelable.Creator<Father2> CREATOR = new Parcelable.Creator<Father2>() {

    public Father2 createFromParcel(Parcel in) {
        return new Father2(in);
    }

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

};

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

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeInt(mField);
    dest.writeInt(mAnotherEnum.ordinal());
}

}

then we can do:

AnotherEnum anotherEnum = AnotherEnum.Z;
intent.putExtra("Serializable2", AnotherEnum.X);   
intent.putExtra("Parcelable2", new Father2(AnotherEnum.X, 7));

Consider Following enum ::

public static  enum MyEnum {
    ValueA,
    ValueB
}

For Passing ::

 Intent mainIntent = new Intent(this,MyActivity.class);
 mainIntent.putExtra("ENUM_CONST", MyEnum.ValueA);
 this.startActivity(mainIntent);

To retrieve back from the intent/bundle/arguments ::

 MyEnum myEnum = (MyEnum) intent.getSerializableExtra("ENUM_CONST");

I think your best bet is going to be to convert those lists into something parcelable such as a string (or map?) to get it to the Activity. Then the Activity will have to convert it back to an array.

Implementing custom parcelables is a pain in the neck IMHO so I would avoid it if possible.


It may be possible to make your Enum implement Serializable then you can pass it via the Intent, as there is a method for passing it as a serializable. The advice to use int instead of enum is bogus. Enums are used to make your code easier to read and easier to maintain. It would a large step backwards into the dark ages to not be able to use Enums.


If you really need to, you could serialize an enum as a String, using name() and valueOf(String), as follows:

 class Example implements Parcelable { 
   public enum Foo { BAR, BAZ }

   public Foo fooValue;

   public void writeToParcel(Parcel dest, int flags) {
      parcel.writeString(fooValue == null ? null : fooValue.name());
   }

   public static final Creator<Example> CREATOR = new Creator<Example>() {
     public Example createFromParcel(Parcel source) {        
       Example e = new Example();
       String s = source.readString(); 
       if (s != null) e.fooValue = Foo.valueOf(s);
       return e;
     }
   }
 }

This obviously doesn't work if your enums have mutable state (which they shouldn't, really).