我有一个活动,启动时需要访问两个不同的数组列表。两个列表都是我自己创建的不同对象。
基本上,我需要一种方法来将这些对象从Intent传递给活动。我可以使用addExtras(),但这需要一个Parceable兼容类。我可以使我的类传递序列化,但据我所知,这减慢了程序。
我有什么选择?
我可以传递一个Enum吗?
题外话:有没有一种方法可以将参数从Intent传递给Activity构造函数?
我有一个活动,启动时需要访问两个不同的数组列表。两个列表都是我自己创建的不同对象。
基本上,我需要一种方法来将这些对象从Intent传递给活动。我可以使用addExtras(),但这需要一个Parceable兼容类。我可以使我的类传递序列化,但据我所知,这减慢了程序。
我有什么选择?
我可以传递一个Enum吗?
题外话:有没有一种方法可以将参数从Intent传递给Activity构造函数?
当前回答
如果你只是想发送一个枚举,你可以这样做:
首先声明一个包含一些值的枚举(可以通过intent传递):
public enum MyEnum {
ENUM_ZERO(0),
ENUM_ONE(1),
ENUM_TWO(2),
ENUM_THREE(3);
private int intValue;
MyEnum(int intValue) {
this.intValue = intValue;
}
public int getIntValue() {
return intValue;
}
public static MyEnum getEnumByValue(int intValue) {
switch (intValue) {
case 0:
return ENUM_ZERO;
case 1:
return ENUM_ONE;
case 2:
return ENUM_TWO;
case 3:
return ENUM_THREE;
default:
return null;
}
}
}
然后:
intent.putExtra("EnumValue", MyEnum.ENUM_THREE.getIntValue());
当你想要得到它时:
NotificationController.MyEnum myEnum = NotificationController.MyEnum.getEnumByValue(intent.getIntExtra("EnumValue",-1);
小菜一碟!
其他回答
这是一个老问题,但每个人都没有提到枚举实际上是可序列化的,因此可以完美地添加到一个额外的意图。是这样的:
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: (通用的,可重用的,与enum解耦的)
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):
已经有一段时间了,但既然现在我们有了Kotlin,我想我应该为新范例添加另一个选项。在这里,我们可以使用扩展函数和具体化类型(在编译时保留类型)。
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] }
这样做有几个好处。
我们不需要中间对象的“开销”来执行序列化,因为内联将用函数内部的代码替换调用,所有这些都已经完成。 这些功能更加熟悉,因为它们与SDK的功能相似。 IDE将自动完成这些功能,这意味着您不需要事先了解实用工具类。
其中一个缺点是,如果我们改变Emums的顺序,那么任何旧的参考都将不起作用。这可能是一个问题,比如挂起意图中的intent,因为它们可能在更新后仍然存在。然而,对于其余的时间,它应该是可以的。
需要注意的是,如果重命名任何值,其他解决方案(如使用名称而不是位置)也会失败。不过,在这些情况下,我们会得到一个异常,而不是错误的Enum值。
用法:
// Sender usage
intent.putExtra(AwesomeEnum.SOMETHING)
// Receiver usage
val result = intent.getEnumExtra<AwesomeEnum>()
要按意图传递枚举,可以将enum转换为整数。
Ex:
public enum Num{A ,B}
发送(enum to integer):
Num send = Num.A;
intent.putExtra("TEST", send.ordinal());
接收(整数到enum):
Num rev;
int temp = intent.getIntExtra("TEST", -1);
if(temp >= 0 && temp < Num.values().length)
rev = Num.values()[temp];
致以最亲切的问候。 :)
我认为最好的办法是将这些列表转换为一些可打包的东西,如字符串(或映射?),以将其传递给活动。然后Activity将不得不将其转换回数组。
实现自定义包装是一个痛苦的脖子,所以我将尽可能避免它。
不要使用枚举。不使用枚举的第78个理由。:)使用整数,可以通过Bundle和Parcelable轻松远程。
考虑以下enum::
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");