【问题标题】:Extending the Intent class ... received ClassCastException扩展 Intent 类...收到 ClassCastException
【发布时间】:2020-09-26 02:45:10
【问题描述】:

我正在尝试创建一个增强的Intent 类(我称之为DataIntent),使其能够容纳对象类型的“有效负载”(而不是使用它为Uri 提供的内置功能) )。 DataIntent 扩展了 Android 的 Intent 类。

我的Activity 创建扩展对象没有任何问题,startActivityForResult() 的调用也没有任何问题。但是,在我响应Activity 时,当我调用getIntent() 方法并尝试将其转换为我的DataIntent 时,我将抛出ClassCastException

我意识到这可能是一个非常愚蠢的问题 - 提前 1,000 个请求 - 但有谁知道为什么我不能将其转换为 DataIntent,因为这是用于启动新的 ActivityDataIntentIntent 的孩子吗?

DataIntent dataIntent = (DataIntent)getIntent(); 
 // invoked inside the responding Activity instance - throws a ClassCastException

【问题讨论】:

  • 你为什么要这样做?你知道http://developer.android.com/reference/android/content/Intent.html#putExtra(java.lang.String, android.os.Parcelable) 吗?
  • 我宁愿远离 Parcelable 接口,因为它不必要地“沉重” - 与简单地分配对我的对象的引用(通过序列化过程进行的所有脱水/再水化)相比。

标签: android


【解决方案1】:

你不能这样做,对不起。您需要将数据放在 Intent 中。 Intent 对象在进程之间移动,因此您返回的实例与您创建的实例不同。

【讨论】:

  • 啊。好吧,这是有道理的。我确信这在某处有记录,我只是还没有看到它。如果 Google 将该类标记为 final 会很有帮助,这样我们就不会尝试扩展它。我希望避免使用 Parcelable 接口,但我想这会迫使我动手。谢谢hackbod。
  • 还有其他发送数据的方式,但听起来您想将其发送到其他应用程序。就像 hackbod 所说,您不能跨进程边界传递活动对象。
  • 其实没有。我只需要在同一个应用程序中发送它,但由于架构显然是这样实现的,因此我的接收 Activity 很可能处于不同的进程中,因此原始 Intent 引用不再有效,这对我接收的原因是有道理的ClassCastException。
【解决方案2】:

我做了同样的事情 CirrusFlyer。在开始实现它之前,我还寻找了 final 关键字。 Google 应将 Intent 类标记为 final。

【讨论】:

    【解决方案3】:

    您可以并且应该扩展 Intent,但您必须了解 Intent 的用途。

    #1 Intent 必须是可打包的,以支持在应用重新启动时保留 Intent 数据(由于内存限制、trimMemory 等而崩溃)。

    #2 理解调用者构造的Intent,并不是提供给Activity的Intent。这是由于项目#1。因此,任何对象引用都会丢失,而且是个坏主意——记住它需要可拆分。

    #3 Intent 应该只包含活动(或其他)的数据上下文。因此,您不应将数据页面放入意图中,而应包含 id 或键,或任何必要的上下文数据,以重新获取活动(或其他)的数据。

    现在...为什么要扩展 Intent?为了好的合同!

    意图本身就是糟糕的合同,太松散了。有些人创建静态方法助手,但有更好的方法。

    如果 ABCActivity 需要“A”“B”和“C”才能正常执行。通用意图无法描述这一点,我们将依赖没有人会阅读的文档。

    相反,我们可以创建一个 ABCIntent,其构造函数需要 A、B 和 C。这将创建一个关于加载活动所需内容的明确约定。我们可以使用静态方法来做到这一点,但是 ABCIntent 也可以为 A B C 提供 getter,使其成为一个干净的封装合约,用于描述加载活动的要求以及如何获取数据。

    有一个警告,我们需要一个私有构造函数来从通用意图构造我们的 ABCIntent 以继承额外内容。

    public ABCActivity extends Activity {
      private ABCIntent intent;
      
      public static ABCIntent extends Intent {
        private ABCIntent(Intent intent) {
          super(intent);
        }
    
        public ABCIntent(A a, B b, C c) {
          putExtra("EXTRA_A", A.serialize(a));
          putExtra("EXTRA_B", B.serialize(b));
          putExtra("EXTRA_C", C.serialize(c));
        }
    
        public A getA() { return A.deserialize(getExtra("EXTRA_A")); }
        public B getB() { return B.deserialize(getExtra("EXTRB_B")); }
        public C getC() { return C.deserialize(getExtra("EXTRC_C")); }
      }
    
      @Override
      protected ABCIntent getIntent() {
        return intent == null ? (intent = new ABCIntent(super.getIntent())) : intent;
      }
    
      @Override
      protected void onCreate( ... ) {
        A a = getIntent().getA();
        B b = getIntent().getB();
        C c = getIntent().getC();
    
        // TODO: re-obtain activity state based on A, B, C then render
      }
    }
    

    请注意,我们从意图构造 ABCIntent。 ABCIntent 继承了 Intent Extras。

    现在你有一个很好的封装类,它的工作是为活动定义契约并为活动提供契约数据。

    如果您是该项目的新工程师,您将无法误解如何使用它。没有可阅读的文档。

    【讨论】:

      猜你喜欢
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 2016-04-14
      • 1970-01-01
      • 2017-05-23
      • 2015-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多