android - 通过 Intent 传递枚举或对象(最佳解决方案)

标签 android

我有一个 Activity ,在启动时需要访问两个不同的 ArrayList。这两个列表都是我自己创建的不同对象。

基本上,我需要一种将这些对象从 Intent 传递给 Activity 的方法。我可以使用 addExtras() 但这需要 Parceable 兼容类。我可以让我的类传递可序列化,但据我所知,这会减慢程序的速度。

我有什么选择?

我可以传递一个枚举吗?

顺便说一句:有没有办法将参数从 Intent 传递给 Activity 构造函数?

最佳答案

这是一个老问题,但每个人都没有提到枚举实际上是 Serializable 因此可以完美地添加到 Intent 作为额外的。像这样:

public enum AwesomeEnum {
  SOMETHING, OTHER;
}

intent.putExtra("AwesomeEnum", AwesomeEnum.SOMETHING);

AwesomeEnum result = (AwesomeEnum) intent.getSerializableExtra("AwesomeEnum");

使用静态或应用程序范围变量的建议是一个非常糟糕的主意。这确实将您的 Activity 与状态管理系统相结合,并且很难维护、调试和问题绑定(bind)。


替代方案:

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,它将用函数内的代码替换调用。<
  • 这些功能更熟悉,因为它们与 SDK 的功能相似。
  • IDE 将自动完成这些功能,这意味着您无需事先了解实用程序类。

其中一个缺点是,如果我们更改 Emums 的顺序,那么任何旧的引用都将不起作用。这可能是待处理 Intent 中的 Intent 之类的问题,因为它们可能会在更新后继续存在。不过,在剩下的时间里,应该没问题。

请务必注意,如果我们重命名任何值,其他解决方案(例如使用名称而不是位置)也会失败。虽然在这些情况下,我们会得到一个异常而不是错误的 Enum 值。

用法:

// Sender usage
intent.putExtra(AwesomeEnum.SOMETHING)
// Receiver usage
val result = intent.getEnumExtra<AwesomeEnum>()

关于android - 通过 Intent 传递枚举或对象(最佳解决方案),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2836256/

相关文章:

android - RxJava 中的异步任务

Android应用——三个问题

android - 创建文件时android中的权限被拒绝

android - show.(getFragmentManager) 扩展 Fragment 而不是 FragmentActivity

android - 我如何在 Android 平台上使用 OpenGL ES 绘制一些 unicode 字符,例如中文

android - 使用 BottomAppBar 或 BottomNavigationView 创建自定义底部 View

android - Bazel 主机(x86 linux)linkopts 传播到目标(android)

android - 自定义标题栏中的MvvmCross绑定(bind)

java - 放置在相对布局中时不出现 Admob 横幅

android - 如何更新可组合函数内的 RecyclerView 的数据?