Answers:
这是一个古老的问题,但是每个人都没有提到枚举实际上是枚举Serializable
,因此可以完美地将Enums 作为额外的东西添加到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);
选项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] }
这样做有一些好处。
inline
这将使用函数内的代码替换调用。缺点之一是,如果我们更改Emums的顺序,则任何旧的参考将不起作用。这可能与挂起的Intent中的Intent之类的问题有关,因为它们可能会在更新后幸存下来。但是,在其余时间里应该没问题。
重要的是要注意,如果重命名任何值,其他解决方案(例如使用名称代替位置)也将失败。尽管在这种情况下,我们得到的是异常而不是错误的Enum值。
用法:
// 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 }
不理想,但应该可以。
您可以使枚举实现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);
如果支持字符串,则应该可以毫无问题地传递枚举值。
为了通过意图传递枚举,可以将枚举转换为整数。
例如:
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()
和将枚举序列化为String,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;
}
}
}
如果您的枚举具有可变状态(这实际上是不应该的),则这显然不起作用。
可能有可能使您的Enum实现序列化,然后可以通过Intent传递它,因为有一种方法可以将其作为序列化传递。使用int代替枚举的建议是虚假的。枚举用于使您的代码更易于阅读和维护。如果不能使用枚举,将向后退一步,进入黑暗时代。
关于Oderik的帖子:
您可以使枚举实现Parcelable,这对于枚举非常简单:
公共枚举MyEnum实现Parcelable {...}然后可以使用Intent.putExtra(String,Parcelable)。
如果定义MyEnum变量myEnum,然后执行intent.putExtra(“ Parcelable1”,myEnum),则会收到“ Intent类型的方法putExtra(String,Parcelable)模棱两可”的错误消息。因为也有一个Intent.putExtra(String,Parcelable)方法,并且原始的“ Enum”类型本身实现了Serializable接口,所以编译器不知道选择哪种方法(intent.putExtra(String,Parcelable /或Serializable))。
建议从MyEnum中删除Parcelable接口,然后将核心代码移动到wrap类的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);
bundle.putExtra("key", AnotherEnum.X.ordinal())
。
您可以使用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作为附加值传递,然后使用其值将其从枚举中拉出。
我喜欢简单。
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;
}
}
考虑以下枚举::
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");
如果您只想发送一个枚举,则可以执行以下操作:
首先声明一个包含一些值的枚举(可以通过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);
小菜一碟!
inline fun <reified T : Enum<T>> Intent.putExtra(enumVal: T, key: String? = T::class.qualifiedName): Intent =
putExtra(key, enumVal.ordinal)
inline fun <reified T: Enum<T>> Intent.getEnumExtra(key: String? = T::class.qualifiedName): T? =
getIntExtra(key, -1)
.takeUnless { it == -1 }
?.let { T::class.java.enumConstants[it] }
这使您可以灵活地传递多个相同的枚举类型,或者默认使用类名。
// Add to gradle
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
// Import the extension functions
import path.to.my.kotlin.script.putExtra
import path.to.my.kotlin.script.getEnumExtra
// To Send
intent.putExtra(MyEnumClass.VALUE)
// To Receive
val result = intent.getEnumExtra<MyEnumClass>()
不要使用枚举。原因#78不使用枚举。:)使用整数,可以很容易地通过Bundle和Parcelable对其进行远程控制。
mEnum.ordinal()
呢?它返回元素的位置
Enum.ordinal()
在编译时固定。注释唯一适用的时间是在具有不同枚举版本的应用程序之间或在更改枚举中元素顺序的应用程序更新之间传递数据。每当您使用非原始的东西时,这种事情都是危险的。在单个应用程序中的活动之间传递意图时,Enum.ordinal()
应该完全安全。