Передача перечисления или объекта через намерение (лучшее решение)
У меня есть деятельность, которая при запуске нуждается в доступе к двум различным ArrayLists. Оба списка-это разные объекты, которые я создал сам.
в основном мне нужен способ передать эти объекты в действие из намерения. Я могу использовать addExtras (), но для этого требуется Parceable совместимый класс. Я мог бы сделать мои классы для передачи сериализуемыми, но, как я понимаю, это замедляет программу.
Каковы мои варианты?
могу ли я передать Перечисление?
в сторону: есть ли способ передать параметры конструктору действия из намерения?
12 ответов:
это старый вопрос, но все не упоминают, что перечисления на самом деле
Serializableи поэтому вполне может быть добавлен к намерению в качестве дополнительного. Вот так:public enum AwesomeEnum { SOMETHING, OTHER; }; intent.putExtra("AwesomeEnum", AwesomeEnum.SOMETHING); AwesomeEnum result = (AwesomeEnum) intent.getSerializableExtra("AwesomeEnum");предложение использовать статические или переменные приложения-это очень плохая идея. Это действительно связывает вашу деятельность с системой управления государством, и ее трудно поддерживать, отлаживать и решать проблемы.
варианты:
хороший момент был отмечен 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);
вы можете сделать свой перечисление реализовать 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]; } }; }затем вы можете использовать намерение.putExtra (String, Parcelable).
обновление: обратите внимание на комментарий wreckgar, что
enum.values()выделяет новый массив при каждом вызове.
вы можете передать перечисление в виде строки.
public enum CountType { ONE, TWO, THREE } private CountType count; count = ONE; String countString = count.name(); CountType countToo = CountType.valueOf(countString);заданные строки поддерживаются, вы должны быть в состоянии передать значение перечисления по без проблем.
для передачи перечисления по намерению, вы можете преобразовать перечисление в целое число.
Ex:
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];С наилучшими пожеланиями. :)
Если вам действительно нужно, вы можете сериализовать перечисление в виде строки, используя
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; } } }это, очевидно, не работает, если ваши перечисления имеют изменяемое состояние (чего они не должны, на самом деле).
возможно, вы можете сделать свой перечислительный инструмент Сериализуемым, тогда вы можете передать его через намерение, так как есть метод для передачи его как сериализуемого. Совет использовать int вместо enum является фиктивным. Перечисления используются для облегчения чтения и обслуживания кода. Это был бы большой шаг назад в темные века, чтобы не иметь возможности использовать перечисления.
о посте Одерика:
вы можете сделать свой перечисление реализовать Parcelable, который довольно легко для перечислений:
public enum MyEnum реализует Parcelable { ... } Вы можете использовать намерение.putExtra (String, Parcelable).
Если вы определяете переменную MyEnum myEnum, то выполните намерение.putExtra ("Parcelable1", myEnum), вы получите сообщение об ошибке" метод putExtra (String, Parcelable) неоднозначен для типа Intent". потому что там это тоже намерение.метод putExtra(String, Parcelable) и исходный тип Enum сами реализуют сериализуемый интерфейс, поэтому компилятор не знает, какой метод (intent.putExtra (String, Parcelable/or Serializable)).
предложите удалить интерфейс Parcelable из MyEnum и переместить основной код в реализацию Parcelable класса wrap, например (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));
вы можете использовать конструктор 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 в качестве дополнительных, а затем вытащить его из перечисления, используя его значение.
мне нравится просто.
- активность Фреда имеет два режима --
HAPPYиSAD.- создать статическую
IntentFactoryчто создаетIntentдля вас. Передай емуModeвы хотите.- The
IntentFactoryиспользует имяModeкласс как имя на дополнительные.- The
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; } }
Я думаю, что ваш лучший выбор будет заключаться в том, чтобы преобразовать эти списки в нечто разбитое на части, такое как строка (или карта?) чтобы получить его к деятельности. Затем действие должно будет преобразовать его обратно в массив.
реализация пользовательских parcelables-это боль в шее IMHO, поэтому я бы избегал ее, если это возможно.
рассмотрим следующие перечисления::
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");
Не используйте перечисления. Причина № 78 не использовать перечисления. :) Используйте целые числа, которые можно легко удалить через Bundle и Parcelable.
Comments