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

前端 未结 15 831
时光取名叫无心
时光取名叫无心 2020-12-04 05:41

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 pa

相关标签:
15条回答
  • 2020-12-04 06:11

    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.

    0 讨论(0)
  • 2020-12-04 06:13

    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).

    0 讨论(0)
  • 2020-12-04 06:14

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

    0 讨论(0)
  • 2020-12-04 06:17

    This is an old question, but everybody fails to mention that Enums are actually Serializable and therefore can perfectly be added to an Intent as an extra. Like this:

    public enum AwesomeEnum {
      SOMETHING, OTHER;
    }
    
    intent.putExtra("AwesomeEnum", AwesomeEnum.SOMETHING);
    
    AwesomeEnum result = (AwesomeEnum) intent.getSerializableExtra("AwesomeEnum");
    

    The suggestion to use static or application-wide variables is a really bad idea. This really couples your activities to a state managing system, and it is hard to maintain, debug and problem bound.


    ALTERNATIVES:

    A good point was noted by tedzyc about the fact that the solution provided by Oderik gives you an error. However, the alternative offered is a bit cumbersome to use (even using generics).

    If you are really worried about the performance of adding the enum to an Intent I propose these alternatives instead:

    OPTION 1:

    public enum AwesomeEnum {
      SOMETHING, OTHER;
      private static final String name = AwesomeEnum.class.getName();
      public void attachTo(Intent intent) {
        intent.putExtra(name, ordinal());
      }
      public static AwesomeEnum detachFrom(Intent intent) {
        if(!intent.hasExtra(name)) throw new IllegalStateException();
        return values()[intent.getIntExtra(name, -1)];
      }
    }
    

    Usage:

    // Sender usage
    AwesomeEnum.SOMETHING.attachTo(intent);
    // Receiver usage
    AwesomeEnum result = AwesomeEnum.detachFrom(intent);
    

    OPTION 2: (generic, reusable and decoupled from the enum)

    public final class EnumUtil {
        public static class Serializer<T extends Enum<T>> extends Deserializer<T> {
            private T victim;
            @SuppressWarnings("unchecked") 
            public Serializer(T victim) {
                super((Class<T>) victim.getClass());
                this.victim = victim;
            }
            public void to(Intent intent) {
                intent.putExtra(name, victim.ordinal());
            }
        }
        public static class Deserializer<T extends Enum<T>> {
            protected Class<T> victimType;
            protected String name;
            public Deserializer(Class<T> victimType) {
                this.victimType = victimType;
                this.name = victimType.getName();
            }
            public T from(Intent intent) {
                if (!intent.hasExtra(name)) throw new IllegalStateException();
                return victimType.getEnumConstants()[intent.getIntExtra(name, -1)];
            }
        }
        public static <T extends Enum<T>> Deserializer<T> deserialize(Class<T> victim) {
            return new Deserializer<T>(victim);
        }
        public static <T extends Enum<T>> Serializer<T> serialize(T victim) {
            return new Serializer<T>(victim);
        }
    }
    

    Usage:

    // Sender usage
    EnumUtil.serialize(AwesomeEnum.Something).to(intent);
    // Receiver usage
    AwesomeEnum result = 
    EnumUtil.deserialize(AwesomeEnum.class).from(intent);
    

    OPTION 3 (with Kotlin):

    It's been a while, but since now we have Kotlin, I thought I would add another option for the new paradigm. Here we can make use of extension functions and reified types (which retains the type when compiling).

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

    There are a few benefits of doing it this way.

    • We don't require the "overhead" of an intermediary object to do the serialization as it's all done in place thanks to inline which will replace the calls with the code inside the function.
    • The functions are more familiar as they are similar to the SDK ones.
    • The IDE will autocomplete these functions which means there is no need to have previous knowledge of the utility class.

    One of the downsides is that, if we change the order of the Emums, then any old reference will not work. This can be an issue with things like Intents inside pending intents as they may survive updates. However, for the rest of the time, it should be ok.

    It's important to note that other solutions, like using the name instead of the position, will also fail if we rename any of the values. Although, in those cases, we get an exception instead of the incorrect Enum value.

    Usage:

    // Sender usage
    intent.putExtra(AwesomeEnum.SOMETHING)
    // Receiver usage
    val result = intent.getEnumExtra<AwesomeEnum>()
    
    0 讨论(0)
  • 2020-12-04 06:21

    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.

    0 讨论(0)
  • 2020-12-04 06:23

    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. :)

    0 讨论(0)
提交回复
热议问题