首页 文章

通过意图传递枚举或对象(最佳解决方案)

提问于
浏览
176

我有一个活动,启动时需要访问两个不同的ArrayLists . 两个列表都是我自己创建的不同对象 .

基本上我需要一种方法将这些对象从Intent传递给活动 . 我可以使用addExtras()但这需要一个Parceable兼容类 . 我可以让我的类通过序列化,但据我所知,这会减慢程序的速度 .

我有什么选择?

我可以通过枚举吗?

旁白:有没有办法从Intent将参数传递给Activity Constructor?

12 回答

  • 459

    有可能使您的Enum实现Serializable然后您可以通过Intent传递它,因为有一种方法可以将它作为可序列化传递 . 使用int而不是枚举的建议是假的 . 枚举用于使代码更易于阅读和维护 . 它将向黑暗时代倒退一大步,无法使用Enums .

  • -1

    这是一个古老的问题,但每个人都没有提到Enums实际上是 Serializable 因此可以完美地添加到Intent作为额外的 . 像这样:

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

    使用静态或应用程序范围变量的建议是一个非常糟糕的主意 . 这确实将您的活动与状态管理系统结合在一起,很难维护,调试和解决问题 .


    ALTERNATIVES:

    tedzyc注意到Oderik提供的解决方案给您一个错误,这是一个很好的观点 . 然而,提供的替代方案有点崩溃 - 一些使用(甚至使用泛型) .

    如果您真的担心将枚举添加到意图中的表现,我建议使用这些替代方案:

    选项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)];
      }
    }
    

    用法:

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

    选项2 :(通用,可重用和与枚举分离)

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

    用法:

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

    你可以使你的enum实现Parcelable,这对枚举非常简单:

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

    然后,您可以使用Intent.putExtra(String,Parcelable) .

    更新:请注意wreckgar的评论, enum.values() 在每次通话时分配一个新阵列 .

  • 2

    您可以将枚举作为字符串传递 .

    public enum CountType {
        ONE,
        TWO,
        THREE
    }
    
    private CountType count;
    count = ONE;
    
    String countString = count.name();
    
    CountType countToo = CountType.valueOf(countString);
    

    在支持字符串的情况下,您应该能够毫无问题地传递枚举值 .

  • 0

    要通过意图传递枚举,您可以将枚举转换为整数 .

    例如:

    public enum Num{A ,B}
    

    发送(枚举为整数):

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

    接收(整数到枚举):

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

    最好的祝福 . :)

  • 24

    如果您确实需要,可以使用 name()valueOf(String) 将枚举序列化为String,如下所示:

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

    如果你的枚举有可变状态(他们不应该,真的),这显然不起作用 .

  • 2

    关于Oderik的帖子:

    你可以使你的枚举实现Parcelable对枚举来说非常容易:public enum MyEnum实现了Parcelable 你可以使用Intent.putExtra(String,Parcelable) .

    如果你定义一个MyEnum变量myEnum,然后执行intent.putExtra(“Parcelable1”,myEnum),你会得到一个“方法putExtra(String,Parcelable)对于Intent类型是不明确的”错误信息 . 因为还有一个Intent.putExtra(String,Parcelable)方法,而原始的'Enum'类型本身实现了Serializable接口,所以编译器不知道选择哪个方法(intent.putExtra(String,Parcelable /或Serializable)) .

    建议从MyEnum中删除Parcelable接口,并将核心代码移动到wrap类'Parcelable实现中,就像这样(Father2是一个Parcelable并包含一个枚举字段):

    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());
    }
    
    }
    

    然后我们可以这样做:

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

    你可以使用enum的enum构造函数来获得原始数据类型 .

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

    你可以使用传递int作为额外的东西然后使用它的值从枚举中拉出它 .

  • 4

    我喜欢简单 .

    • Fred活动有两种模式 - HAPPYSAD .

    • 创建一个静态 IntentFactory ,为您创建 Intent . 把它传递给你想要的 Mode .

    • IntentFactory 使用 Mode 类的名称作为额外名称 .

    • IntentFactory 使用 name()Mode 转换为 String

    • 进入 onCreate 后,使用此信息转换回 Mode .

    • 您也可以使用 ordinal()Mode.values() . 我喜欢字符串,因为我可以在调试器中看到它们 .

    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;
        }
    }
    
  • 112

    我认为你最好的选择是将这些列表转换成可以分配的东西,比如字符串(或 Map ?),以便将它转换为Activity . 然后Activity必须将其转换回数组 .

    实施自定义parcelables是脖子上的痛苦恕我直言,所以我会尽可能避免它 .

  • 19

    考虑以下enum ::

    public static  enum MyEnum {
        ValueA,
        ValueB
    }
    

    传球::

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

    从intent / bundle / arguments中检索回::

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

    不要使用枚举 . 原因#78不使用枚举 . :)使用整数,可以通过Bundle和Parcelable轻松地远程控制 .

相关问题