As I understand it, an activity being destroyed is not equivalently to an activity being finished.
finish()
), or by the user pressing the back key (which implicitly calls finish()
).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:
c.finish()
:
c
is destroyed.b.finishActivity()
:
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);
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.
Can't finish a destroyed activity directly, so just finish()
it in its onCreate()
(suggested by @Labeeb P). Here's how:
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;
}
SharedPreferences
(suggested by @Labeeb P).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;
}
...
}
Calling finish()
in onCreate()
is actually a legimate operation, as it is mentioned in the doc:
... you might call
finish()
from withinonCreate()
to destroy the activity. In this case, the system immediately callsonDestroy()
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.