13

据我了解,正在销毁的活动并不等同于正在完成的活动。

  • 完成的
    • 该活动从后台堆栈中删除。
    • 它可以由程序触发(例如通过调用finish()),或者由用户按下后退键(隐式调用finish())触发。
    • 完成一项活动将摧毁它。
  • 毁坏
    • Android 操作系统可能会破坏不可见的活动以恢复内存。当用户导航回活动时,活动将被重新创建。
    • 当用户旋转屏幕时,Activity 被销毁并重新创建。
    • 参考:重新创建活动

那么我该如何完成一个被破坏的活动呢?该finish()方法需要一个Activity对象,但如果活动被破坏,我没有Activity对象 - 我不应该持有对被破坏活动的引用,是吗?


案例分析:

我有一个活动a,它开始b,然后开始c(使用Activity.startActivity()),所以现在后面的堆栈是:

a → b → c

c中,用户填写表格并点击提交按钮。使用 . 向远程服务器发出网络请求AsyncTask。任务完成后,我举杯祝酒,并通过调用c.finish(). 完美的。

现在考虑这种情况:

当异步任务正在进行时,用户切换到另一个应用程序。然后,由于内存限制,Android 操作系统决定销毁所有 3 个活动 ( a, b, )。c稍后,异步任务完成。现在我该如何完成c

我试过的:

  • 致电c.finish()
    • 不能,因为c被破坏了。
  • 致电b.finishActivity()
    • 不能,因为b被破坏了。
  • 使用Context.startActivity()withFLAG_ACTIVITY_CLEAR_TOP以提升b到顶部,从而完成c

    // appContext is an application context, not an activity context (which I don't have)
    Intent intent = new Intent(appContext, B.class);    // B is b's class.
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    appContext.startActivity(intent);
    
    • 失败,appContext.startActivity()抛出异常:

android.util.AndroidRuntimeException:从 Activity 上下文外部调用 startActivity() 需要 FLAG_ACTIVITY_NEW_TASK 标志。这真的是你想要的吗?

编辑: 澄清:我需要等到异步任务完成并c根据服务器的响应决定是否完成。

4

6 回答 6

3

android.util.AndroidRuntimeException:从 Activity 上下文外部调用 startActivity() 需要 FLAG_ACTIVITY_NEW_TASK 标志。这真的是你想要的吗?


  • 当您从后台线程或服务启动活动时,通常会发生此异常。每当您需要“启动器” 类型的行为时,您都需要传递
    FLAG_ACTIVITY_NEW_TASK标志。

    • 只需添加mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);以避免此异常。

  • 不建议您尝试杀死活动的方式,让android自行处理。完成已经被破坏的活动没有任何意义。

现在,你能做什么?

  • 如果您在应用程序不在前台时完成活动时遇到问题,您可以做的是实施安全检查,仅当应用程序处于前台时才能完成活动以进入后台活动,否则只需跳过该步骤。

  • 我认为您正试图在应用程序处于后台时终止该活动。这样做似乎有点困难,但是您可以使用onUserLeaveHint来决定应用程序何时进入后台以完成活动,或者您可以通过添加来完成finish();活动onStop()。只需确保 asynctaskonPost()不会再次完成它以避免异常。

  • 查看android:clearTaskOnLaunch属性并将其设置为 true。

    谷歌文档说这个属性是:

    例如,有人从主屏幕启动活动 P,然后从那里转到活动 Q。用户接下来按 Home,然后返回到活动 P。通常,用户会看到活动 Q,因为那是他们最后一次做P的任务。但是,如果 P 将此标志设置为“true”,则当用户按下 Home 并且任务进入后台时,它上面的所有活动(在本例中为 Q)都将被删除。所以用户返回任务时只看到P。

    我认为这正是您想要的情况。

希望这会给你一些提示来完成你想要的任务。

于 2013-02-04T06:10:47.310 回答
1

您可以从onPostExecutec 中的方法广播您的操作,并在 a 和 b 中注册广播receiver以接收该操作。然后在那个接收器onRevice方法中完成

c,异步任务,

 void onPostExecute(Long result) {
         ----
         Intent intent1 = new Intent("you custom action");
    context.sendBroadcast(intent1);
     }

ab

registerReceiver(new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {
                finish();

            }
        },new IntentFilter("you custom action"));
于 2013-02-04T06:09:54.323 回答
1

就个人而言,我会使用通知栏来通知用户他的查询状态。

这样,我就可以避免未完成活动的整个问题。只有当用户还没有点击提交按钮时,我才会保持活动未完成。

于 2013-02-04T06:40:43.653 回答
0

关于在活动被销毁之前准确调用的android 手册 onDestroy(),因此您可以在其中调用完成(即使您可以在完全终止活动之前停止您的 bg 线程)。

我们可以假设如果活动被杀死,我们也不对 bg 线程感兴趣,例如,如果 bg 线程要下载需要完成的图像等 - 所以你必须使用服务而不是 asynctask。

于 2013-02-04T06:09:09.290 回答
0

无法直接完成已破坏的活动,因此只需finish()将其放入其中onCreate()(由@Labeeb P建议)。就是这样:

  1. 如果活动在尝试完成时已经被破坏,请在某处保存一个布尔标志。

    if(activity != null)
    {
        // Activity object still valid, so finish() now.
        activity.finish();
    }
    else
    {
        // Activity is destroyed, so save a flag.
        is_activity_pending_finish = true;
    }
    
    • 如果即使应用程序被销毁,标志也需要保留,请使用持久存储,例如SharedPreferences@Labeeb P建议)。
  2. 在活动中onCreate(),检查标志并调用finish()

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
    
        if(is_activity_pending_finish)
        {
            is_activity_pending_finish = false; // Clear the flag.
    
            // This activity should have been finished, so finish it now.
            finish();
            return;
        }
    
        ...
    }
    
    • 如果同一个 Activity 类有多个实例,您可能需要的不仅仅是一个布尔标志来标识要完成的特定活动实例。

调用finish()实际上onCreate()是一个合法的操作,正如文档中提到的那样:

...您可能会finish()从内部调用onCreate()以破坏活动。在这种情况下,系统会立即调用onDestroy()而不调用任何其他生命周期方法。


其他注意事项:

  • 在应用程序处于后台时完成活动可能不是一个好主意,特别是如果它是唯一的活动。确保您不会混淆用户。
  • 为了获得更好的用户体验,如果您在应用程序处于后台时完成了一项活动,您可能需要通知用户。考虑使用toasts(适用于短期通知)或通知(适用于用户可能忘记的长时间操作)(@Stephan Branczyk@dilix建议)。

当然,被销毁的活动并不一定意味着应用程序处于后台(可能还有另一个前台活动)。尽管如此,上述解决方案(调用finish())仍然onCreate()有效。

于 2013-02-05T02:35:53.263 回答
0

当系统试图销毁您的 Activity 时,它会调用onSaveInstanceState. 在这里你可以打电话finish()。就是这样。

Warning: I've never tried this, so I don't know for sure if there are any issues with calling finish() from onSaveInstanceState. If you try this, please comment and let me know how it works out.

于 2014-10-22T20:07:02.683 回答