androidandroid-activityactivity-lifecycle

How to finish destroyed Activity


As I understand it, an activity being destroyed is not equivalently to an activity being finished.

So how do I finish a destroyed activity? The finish() method requires an Activity object, but if the activity is destroyed, I have no Activity object - I am not supposed to be holding a reference to a destroyed activity, am I?


Case study:

I have an activity a, which starts b, which in turn starts c (using Activity.startActivity()), so now the back stack is:

a → b → c

In c, the user fills out a form and tap the Submit button. A network request is made to a remote server using AsyncTask. After the task is completed, I show a toast and finish the activity by calling c.finish(). Perfect.

Now consider this scenario:

While the async task is in progress, the user switches to another app. Then, the Android OS decided to destroy all 3 activities (a, b, c) due to memory constraints. Later, the async task is completed. Now how do I finish c?

What I have tried:

android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

Edit: Clarification: I need to wait until the async task finishes and decide whether to finish c based on server's response.


Solution

  • Can't finish a destroyed activity directly, so just finish() it in its onCreate() (suggested by @Labeeb P). Here's how:

    1. If the activity is already destroyed when trying to finish it, save a boolean flag somewhere instead.

      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;
      }
      
      • If the flag needs to stay even if the app is destroyed, use persistent storage, e.g. SharedPreferences (suggested by @Labeeb P).
    2. In the activity's onCreate(), check the flag and call 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;
          }
      
          ...
      }
      
      • If there're multiple instances of the same Activity class, you may need something more than a boolean flag to identify the specific instance of activity to finish.

    Calling finish() in onCreate() is actually a legimate operation, as it is mentioned in the doc:

    ... you might call finish() from within onCreate() to destroy the activity. In this case, the system immediately calls onDestroy() without calling any of the other lifecycle methods.


    Other considerations:

    Of course, an activity being destroyed doesn't necessary mean that the app is in background (there might be another foreground activity). Still, the above solution (calling finish() in onCreate()) works.