我有一个活动,当开始时需要访问两个不同的 ArrayList。这两个列表都是我自己创建的不同对象。
基本上我需要一种将这些对象从 Intent 传递给活动的方法。我可以使用 addExtras() 但这需要 Parceable 兼容类。我可以让我的类通过可序列化,但据我所知,这会减慢程序的速度。
我有哪些选择?
我可以通过枚举吗?
顺便说一句:有没有办法将参数从 Intent 传递给 Activity 构造函数?
这是一个老问题,但每个人都没有提到枚举实际上是Serializable,因此可以完美地添加到 Intent 作为额外的。像这样:
Serializable
public enum AwesomeEnum { SOMETHING, OTHER; } intent.putExtra("AwesomeEnum", AwesomeEnum.SOMETHING); AwesomeEnum result = (AwesomeEnum) intent.getSerializableExtra("AwesomeEnum");
使用静态或应用程序范围变量的建议是一个非常糟糕的主意。这确实将您的活动与状态管理系统相结合,并且很难维护、调试和问题绑定。
备择方案:
如果您真的担心将枚举添加到 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 的顺序,那么任何旧的引用都将不起作用。这可能是待处理意图中的意图之类的问题,因为它们可能会在更新后继续存在。但是,在剩下的时间里,它应该没问题。
重要的是要注意,如果我们重命名任何值,其他解决方案(例如使用名称而不是位置)也会失败。虽然在这些情况下,我们得到一个异常而不是错误的 Enum 值。
// Sender usage intent.putExtra(AwesomeEnum.SOMETHING) // Receiver usage val result = intent.getEnumExtra<AwesomeEnum>()