Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to finish destroyed Activity

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

  • Finished
    • The activity is removed from the back stack.
    • It can be triggered by the program (e.g. by calling finish()), or by the user pressing the back key (which implicitly calls finish()).
    • Finishing an activity will destroy it.
  • Destroyed
    • The Android OS may destroy an invisible activity to recover memory. The activity will be recreated when the user navigates back to it.
    • The activity is destroyed and recreated when the user rotates the screen.
    • Reference: Recreating an Activity

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:

  • Call c.finish():
    • Can't, because c is destroyed.
  • Call b.finishActivity():
    • Can't, because b is destroyed.
  • Use Context.startActivity() with FLAG_ACTIVITY_CLEAR_TOP so as to raise b to the top, thus finishing 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);
    
    • Failed, appContext.startActivity() throws an exception:

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.

like image 794
Pang Avatar asked Feb 04 '13 05:02

Pang


People also ask

What happens when an activity is destroyed android?

When Android creates and destroys an activity, the activity moves from being launched to running to being destroyed. An activity is running when it's in the foreground of the screen. onCreate() gets called when the activity is first created, and it's where you do your normal activity setup.

What happens to fragment when activity is destroyed?

As Fragment is embedded inside an Activity, it will be killed when Activity is killed.


2 Answers

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

  • This exception used to occur when you are starting an activity from
    the background thread or service. You need to pass
    FLAG_ACTIVITY_NEW_TASK flag whenever you need the "launcher"
    type of behavior.

    • Just add mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); to avoid this exception.

  • The way you are trying to kill the activity is not recommended, let the android handle itself. There isn't any meaning to finish an activity which is already destroyed.

Now, what you can do?

  • If you are facing problem in finishing activity when app is not in foreground, what you can do is to implement a security check which will finish the activity only when app is in foreground to go to back-stack activity or else just skip that step.

  • I think you are trying to kill the activity when app is in background. It seems a little bit difficult to do so, but you can make use of onUserLeaveHint to decide when app is going in the background in-order to finish the activity or you can finish the activity by adding finish(); in onStop(). Just make sure that asynctask's onPost() don't finish it again in-order to avoid the exception.

  • Have a look at android:clearTaskOnLaunch attribute and set it to true.

    Google Doc says about this attribute is:

    for example, that someone launches activity P from the home screen, and from there goes to activity Q. The user next presses Home, and then returns to activity P. Normally, the user would see activity Q, since that is what they were last doing in P's task. However, if P set this flag to "true", all of the activities on top of it (Q in this case) were removed when the user pressed Home and the task went to the background. So the user sees only P when returning to the task.

    and i think this is the exact case which you want.

Hope this will give you some hint to achieve your desired task.

like image 65
Moin Ahmed Avatar answered Nov 15 '22 19:11

Moin Ahmed


you can broadcast your action from the onPostExecute method in c and register a broadcast receiver to receive for that action in a and b. Then do finish in that receiver onRevice method

In c , AsyncTask,

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

In a and b

registerReceiver(new BroadcastReceiver() {

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

            }
        },new IntentFilter("you custom action"));
like image 20
Labeeb Panampullan Avatar answered Nov 15 '22 19:11

Labeeb Panampullan