Передача enum или объекта через намерение (лучшее решение) - PullRequest
193 голосов
/ 14 мая 2010

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

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

Какие у меня варианты?

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

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

Ответы [ 12 ]

495 голосов
/ 17 марта 2012

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

public enum AwesomeEnum {
  SOMETHING, OTHER;
}

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

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

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


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

tedzyc отметил, что решение, предоставленное Oderik , дает вам ошибку. Тем не менее, предоставленная альтернатива немного рушится - некоторые используют (даже используя дженерики).

Если вы действительно беспокоитесь о возможности добавления enum к намерению, я предлагаю вместо этого следующие варианты:

ВАРИАНТ 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);

ВАРИАНТ 3 (с Kotlin):

Прошло много времени, но, поскольку теперь у нас есть Котлин, я подумал, что добавлю еще одну опцию для новой парадигмы. Здесь мы можем использовать функции расширения и расширенные типы (которые сохраняют тип при компиляции).

inline fun <reified T : Enum<T>> Intent.putExtra(victim: T): Intent =
    putExtra(T::class.qualifiedName, victim.ordinal)

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

Есть несколько преимуществ сделать это таким образом.

  • Для выполнения сериализации нам не нужны «издержки» промежуточного объекта, поскольку все это выполняется на месте благодаря inline, который заменит вызовы кодом внутри функции.
  • Функции более знакомы, так как они похожи на функции SDK.
  • Среда IDE будет автоматически завершать эти функции, что означает, что нет необходимости предварительно знать класс утилит.

Использование:

// Sender usage
intent.putExtra(AwesomeEnum.SOMETHING)
// Receiver usage
val result = intent.getEnumExtra<AwesomeEnum>()
113 голосов
/ 21 сентября 2011

Вы можете сделать свой 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 )

24 голосов
/ 09 октября 2012

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

public enum CountType {
    ONE,
    TWO,
    THREE
}

private CountType count;
count = ONE;

String countString = count.name();

CountType countToo = CountType.valueOf(countString);

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

21 голосов
/ 05 августа 2011

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

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

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

15 голосов
/ 20 февраля 2011

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

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

4 голосов
/ 06 июля 2011

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

2 голосов
/ 08 июня 2016

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

2 голосов
/ 23 декабря 2012

о посте Одерика:

Вы можете сделать свой enum реализующим 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)).

Предложите удалить интерфейс Parcelable из MyEnum и переместить основной код в реализацию Parcelable класса wrap, например, как (Father2 является Parcelable и содержит поле enum):

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));
1 голос
/ 05 июня 2013

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

  • У действия Фреда есть два режима - 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;
        }
    }
    
0 голосов
/ 02 января 2013

Рассмотрим следующее 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");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...