Передача перечисления или объекта через намерение (лучшее решение)

У меня есть активность, которая при запуске требует доступа к двум различным ArrayLists. Оба списка - это разные объекты, которые я создал сам.

В принципе, мне нужен способ передать эти объекты в действие из намерения. Я могу использовать addExtras(), но для этого требуется совместимый с Parceable класс. Я мог бы сделать мои классы переданными сериализуемыми, но, как я понимаю, это замедляет работу программы.

Каковы мои варианты?

Могу ли я передать Enum?

Как вариант: существует ли способ передать параметры в конструктор активности из намерения?

Ответ 1

Это старый вопрос, но все не упоминают, что Enums на самом деле Serializable и поэтому могут быть добавлены к намерению в качестве дополнительного. Вот так:

public enum AwesomeEnum {
  SOMETHING, OTHER;
};

intent.putExtra("AwesomeEnum", AwesomeEnum.SOMETHING);

AwesomeEnum result = (AwesomeEnum) intent.getSerializableExtra("AwesomeEnum");

Предложение использовать переменные static или application wide - действительно плохая идея. Это действительно связывает вашу деятельность с системой управления государством, и ее трудно поддерживать, отлаживать и решать проблемы.


АЛЬТЕРНАТИВНЫЕ:

Хороший момент был отмечен 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);

Ответ 2

Вы можете заставить свой 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() выделяет новый массив при каждом вызове.

ОБНОВЛЕНИЕ: Android Studio имеет живой шаблон ParcelableEnum который реализует это решение. (В Windows используйте Ctrl + J)

Ответ 3

Вы можете передать перечисление через строку.

public enum CountType {
    ONE,
    TWO,
    THREE
}

private CountType count;
count = ONE;

String countString = count.name();

CountType countToo = CountType.valueOf(countString);

Указанные строки поддерживаются, вы можете без проблем передавать значение перечисления.

Ответ 4

Для передачи перечисления с помощью намерения вы можете преобразовать enum в integer.

Пример:

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

С уважением. :)

Ответ 5

Если вам действительно нужно, вы можете сериализовать перечисление как строку, используя name() и valueOf(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;
     }
   }
 }

Это явно не работает, если ваши перечисления имеют изменяемое состояние (чего они не должны, действительно).

Ответ 6

Возможно, ваш Enum реализует Serializable, тогда вы можете передать его через Intent, так как есть способ передать его как сериализуемый. Совет использовать int вместо enum является фиктивным. Перечисления используются для упрощения чтения и упрощения вашего кода. Это был бы большой шаг назад в темные века, чтобы не использовать Enums.

Ответ 7

об Oderik post:

Вы можете сделать enum реализовать Parcelable, что довольно просто для перечислений:

public enum MyEnum реализует Parcelable {... } Вы можете использовать Intent.putExtra(String, Parcelable).

Если вы определяете переменную MyEnum myEnum, тогда сделайте aim.putExtra( "Parcelable1", myEnum), вы получите "Метод putExtra (String, Parcelable) неоднозначен для сообщения об ошибке типа Intent". потому что существует также метод Intent.putExtra(String, Parcelable), а оригинальный тип "Enum" реализует интерфейс Serializable, поэтому компилятор не знает, какой метод (aim.putExtra(String, Parcelable/или Serializable)).

Предложите удалить интерфейс Parcelable из MyEnum и переместить основной код в пакетную реализацию 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));

Ответ 8

вы можете использовать конструктор 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 как дополнительные функции, а затем вытащить его из перечисления, используя его значение.

Ответ 9

Мне нравится просто.

  • Активность Fred имеет два режима: HAPPY и SAD.
  • Создайте статический IntentFactory, который создаст для вас Intent. Передайте ему Mode, который вы хотите.
  • IntentFactory использует имя класса Mode как имя дополнительного.
  • IntentFactory преобразует Mode в String, используя name()
  • При входе в 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;
        }
    }
    

Ответ 10

Я думаю, что ваш лучший выбор состоит в том, чтобы преобразовать эти списки во что-то существенное, например строку (или карту?), чтобы получить ее в Activity. Затем Activity будет преобразовывать его обратно в массив.

Реализация пользовательских parcelables - это боль в шее IMHO, поэтому я мог бы избежать этого, если это возможно.

Ответ 11

Рассмотрим следующий enum ::

public static  enum MyEnum {
    ValueA,
    ValueB
}

Для прохождения ::

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

Чтобы вернуть обратно из намерения/пучка/аргументов ::

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

Ответ 12

Не используйте перечисления. Причина № 78 не использовать перечисления.:) Используйте целые числа, которые легко удаляются через Bundle и Parcelable.