【问题标题】:activity not calling onDestroy() after finish()在完成()之后活动未调用 onDestroy()
【发布时间】:2012-02-26 10:24:58
【问题描述】:

我有三项活动,我们称它们为一、二和三。从活动一开始,按下按钮开始活动二。从活动二开始,按下按钮即可开始活动三。

足够简单。

现在,活动三需要可从应用程序访问的一些数据(可能存在也可能不存在)。在 THREE 的 onResume() 方法中,对数据进行检查,如果不存在则完成活动,如下所示:

@Override
protected void onResume() {
    super.onResume();

    /* ... get data from app ... */

    if (data == null) {
        Toast.makeText(this, "Data not found", Toast.LENGTH_SHORT).show();
        finish();
        return;
    }

    /* ... other logic ... */
}

data == null,三完成,销毁并返回二。一切都很好。 现在在 TWO 中,按下后退按钮在 TWO 上调用 finish(),但 TWO 从不调用 onDestroy()。用户返回到 ONE 就好了,但是任何随后返回到 TWO 的意图都不起作用,并且不会引发任何错误。 TWO 处于已完成(并暂停)但从未销毁的状态,因此无法恢复。

那么,在这种情况下,为什么三个重要?如果我删除上面代码块中的finish() 调用,并依靠“自然”完成三(通过使用后退按钮),当用户返回一时,二已被正确销毁。

好吧,这就是真正令人困惑的地方......

留下finish() 调用,我可以通过直接从ONE 启动三个来缓解挂断,然后“自然”完成它(返回按钮)。 THREE 被销毁(第二次)后,TWO 按预期打开。

我读到的所有内容都表明我应该可以在onResume() 内调用finish() 进行活动。但在这种情况下,它会使某些东西处于不良状态,并阻止我破坏调用活动。

想法?还是我把你的大脑翻过来了?

编辑:

进一步探索发现了这颗宝石......

用大约 500 毫秒的 postDelay() 处理程序将 THREE 中的 finish() 调用包围起来,这将允许 TWO 按预期关闭。像这样:

@Override
protected void onResume() {
    super.onResume();

    /* ... get data from app ... */

    if (data == null) {
        Toast.makeText(this, "Data not found", Toast.LENGTH_SHORT).show();
        Handler h = new Handler();
        h.postDelayed(new Runnable() {
            @Override
            public void run() {
                finish();
            }
        }, 500);
        return;
    }

    /* ... other logic ... */
}

不完全是我的修复想法...

【问题讨论】:

  • 这是什么数据?从事物的声音来看,当 THREE 进入 onCreate() 时,该数据应该存在(不为空)。偏远的问题是 onResume() 数据为空的事实吗?或者数据是否会过时、失效或无用?
  • 如果您采用多线程等待,您的架构似乎有严重问题...我有一个可能的答案,但在您回答“数据”是什么以及为什么它在简历中为空之前,我将推迟回答因为它可能/可能不是答案。
  • @GrahamSmith 说实话,你是对的,数据不应该为空。但是在测试一个可能为空的边缘案例时,我们偶然发现了这个问题。如果我们不能很快解决它,我们将忽略边缘案例。 :) 数据是根据意图中的“id”填充的。然后将该“id”传递给应用程序中的公共方法以检索查看数据缓冲区或本地数据库的对象(数据)。
  • @GrahamSmith 让我澄清一下,多线程方法不是我打算做的。有趣的是它以某种方式解决了这个问题。
  • 好的,那么直截了当的问题 - 数据是否仅在 onResume() 上为空,或者它可以在三个的 onCreate() 中为空?

标签: android onresume activity-finish


【解决方案1】:

一个 Activity 未完成/在后按时销毁。

使用

 @Override
    public void onBackPressed()
    {
        finish();
    }

【讨论】:

  • 据我所知,调用 super.onBackPressed() 将完成我的活动。
  • android 文档明确提到onBackPressed() 只调用onPause(),如果要调用onStop()onDestroy(),则取决于JVM 状态。
  • 我还会提到我正在从 onBackPressed() 中调用完成。抱歉,这是一个非常大的应用程序。不止一位开发者。
【解决方案2】:

由于无法发表评论,我就写在这里。

我不是 100% 确定我是否关注了你,但在接近尾声时你提到了这一点

THREE 被销毁(第二次)后,TWO 按预期打开。

你的意思是什么,因为如果我没听错,你说你用一个按钮打开两个,用一个按钮打开三个。那么 TWO 如何按预期打开,或者您的意思是当您退出它时它会转到 onDestroy() ?

我的目标是,如果您查看图 3,也许您会打开更多相同活动的实例,正如 here 中提到的那样。

【讨论】:

  • 基本上,在 ONE 中,用户有按钮可以转到 2 或 3。在挂断发生并且用户重新打开 ONE 后,直接从 ONE 启动到 THREE,然后完成 THREE(通过后退按钮)可以释放阻止 TWO 打开的任何东西。
  • 为什么会出现这种“挂断”?
  • @GrahamSmith 这是百万美元的问题。
【解决方案3】:

由于这个问题只发生在 onResume() [参见 cmets] 我认为这听起来像是状态持久性的问题,而不是修补堆栈。

看看这个 Stack Over Flow Question Saving Android Activity state using Save Instance State

如果 onPause() 将“数据”(我不知道它的对象类型,因为你没有说)保存到 Bundle 然后 onResume() 去获取它。

Google 发现的另一个示例 here,使用 SharedPreferences 代替 Bundle 来实现相同的结果。

总体而言,这意味着您可以处理/防止“数据”为空,因为您可以恢复它,从而节省破坏三个和尝试摆弄堆栈的工作,只需用您的术语保持工作流程“自然”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-24
    相关资源
    最近更新 更多