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



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



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



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



могу ли я передать Перечисление?



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

250   12  

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

    Ничего не найдено.