我有一个活动,启动时需要访问两个不同的ArrayList。这两个列表是我自己创建的不同对象。
基本上,我需要一种从Intent传递这些对象到活动的方法。我可以使用addExtras(),但这需要一个可Parceable兼容的类。我可以将要传递的类设为可序列化的,但据我所知,这会减缓程序的运行速度。
我有哪些选择?
我能传递一个枚举吗?
另外,有没有办法从Intent传递参数给活动构造函数?
我有一个活动,启动时需要访问两个不同的ArrayList。这两个列表是我自己创建的不同对象。
基本上,我需要一种从Intent传递这些对象到活动的方法。我可以使用addExtras(),但这需要一个可Parceable兼容的类。我可以将要传递的类设为可序列化的,但据我所知,这会减缓程序的运行速度。
我有哪些选择?
我能传递一个枚举吗?
另外,有没有办法从Intent传递参数给活动构造函数?
public enum AwesomeEnum {
SOMETHING, OTHER;
}
intent.putExtra("AwesomeEnum", AwesomeEnum.SOMETHING);
AwesomeEnum result = (AwesomeEnum) intent.getSerializableExtra("AwesomeEnum");
替代方案:
tedzyc 指出了一个好的观点,即 Oderik 提供的解决方案会给您带来一个错误。然而,提供的替代方案使用起来有点麻烦(即使使用泛型)。
如果您真的担心将枚举添加到 Intent 的性能问题,我建议使用以下替代方案:
选项 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);
选项三(使用 Kotlin):
虽然已经有一段时间了,但现在我们有了 Kotlin,我认为应该为这种新编程范式添加另一种选择。在这里,我们可以利用扩展函数和 reified 类型(在编译时保留类型)。
inline fun <reified T : Enum<T>> Intent.putExtra(victim: T): Intent =
putExtra(T::class.java.name, victim.ordinal)
inline fun <reified T: Enum<T>> Intent.getEnumExtra(): T? =
getIntExtra(T::class.java.name, -1)
.takeUnless { it == -1 }
?.let { T::class.java.enumConstants[it] }
inline
,它将用函数内部的代码替换调用。// Sender usage
intent.putExtra(AwesomeEnum.SOMETHING)
// Receiver usage
val result = intent.getEnumExtra<AwesomeEnum>()
enum class
类型交叉编译为普通的 Java enum
。我猜更简单的解决方法是让 enum class
实现 Serializable
接口:
enum class AwesomeEnum : Serializable { A, B, C }
虽然不是最理想的解决方案,但应该可以工作。 - pablisco你可以让枚举实现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)
你可以将枚举类型作为字符串传递。
public enum CountType {
ONE,
TWO,
THREE
}
private CountType count;
count = ONE;
String countString = count.name();
CountType countToo = CountType.valueOf(countString);
如果支持字符串,则应该可以轻松地传递枚举的值。
要通过Intent传递枚举类型,您可以将其转换为整数。
例如:
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;
}
}
}
如果您的枚举具有可变状态(实际上不应该这样),那么这显然无法正常工作。
可能可以使您的枚举实现Serializable,然后通过Intent进行传递,因为有一种方法可以将其作为可序列化对象传递。建议使用int而不是enum是错误的。枚举用于使您的代码更易于阅读和维护。不能使用Enums会是一个倒退到黑暗时代的巨大步骤。
这里大部分使用可序列化Parcelable概念的回答都是Java代码,而在Kotlin中更容易实现。
只需将您的枚举类注释为@Parcelize并实现Parcelable接口即可。
@Parcelize
enum class ViewTypes : Parcelable {
TITLE, PRICES, COLORS, SIZES
}
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作为extras传递,然后使用其值从枚举中提取它。
关于Oderik的帖子:
你可以让你的枚举实现Parcelable接口,这对枚举来说非常容易:
public enum MyEnum implements Parcelable { ... } 然后你就可以使用Intent.putExtra(String, Parcelable)了。
如果你定义了一个MyEnum变量myEnum,然后执行intent.putExtra("Parcelable1", myEnum),你会得到一个"The method putExtra(String, Parcelable) is ambiguous for the type Intent"错误消息。因为Intent类中也有一个putExtra(String, Parcelable)方法,并且原始的'Enum'类型本身实现了Serializable接口,所以编译器不知道选择哪个方法(intent.putExtra(String, Parcelable/or Serializable))。
建议从MyEnum中删除Parcelable接口,并将核心代码移动到包装类的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));
intent.putExtra("myEnum", (Parcelable) enumValue);
- Oderikbundle.putExtra("key", AnotherEnum.X.ordinal())
。 - TWiStErRob我喜欢简单。
HAPPY
和 SAD
。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;
}
}