Is there a way to launch an activity when returning to an application after it was terminated to free up memory? Android is attempting to start the previous activity, but some data I need has been cleaned up during termination. If I can push my home activity onto the stack when returning, my app will be able to function properly.
Thanks!
Declare a public static variable somewhere, which is set to true when your main activity has completed its initialization.
In your other activities, in onCreate(), check if this variable is set to true. If not, it means that Android has killed and recreated your process and restarted just the top activity. In this case, just launch the main activity using Intent.FLAG_ACTIVITY_CLEAR_TOP. This will clear the task stack and start your main activity.
This will only work if the main activity is always in the task stack, at the very bottom (root activity). This means that your main activity should NOT call finish() when it launches other activities on top of itself.
Try this:
put an EXTRA value into the intent starting the second activity, anything really, just to indicate it was started from your MainActivity. Then, in the second Activity's onCreate() use getIntent() to obtain the intent that started it. If it contains your extra value, do nothing and let the activity start normally. If it does not, finish() the second Activity and start MainActivity.
Related
When you're in an an Activity (we'll call it A), and you invoke a subsequent Activity (B), perhaps as a result of clicking a button in A, and then RETURN to that prior Activity A, either by clicking the Back button or explicitly calling finish() from within B, it causes A to be completely rebuilt, calling its constructor and its OnCreate() method, etc.
Is there any way to prevent that from happening, so that it actually does return to the prior, already existing, Activity A?
Correct me if I'm wrong, but it should not call onCreate() here's a gross over simplification, but let's say activity's are managed much like a simple stack, let's call it AppStack
When a onCreate() for Activity A is called, the OS pushes the Activity Instance onto the AppStack
________ _________________
Activity|
___A____|_________________
When you click a button on Activity A, it launches a new intent to Activity B
Intent actB = new Intent(this, ActivityB.class);
and subsequently puts Activity A into Stopped state
When Activity B's onCreate() is called the OS pushes that Activity Instance onto the AppStack
________ __________________
Activity|Activity|
___A____|___B____|_________
Now if you call finish() or super.onBackPressed() in Activity B, the OS will pop() the Activity from the AppStack
________ __________________
Activity|
___A____|__________________
When the OS returns to the previous activity, it sees that it is Stopped and begins the process of Resuming it through onResume().
Now if there is some data that you require to be persistent, you can add it in by Overriding onResume()
Check out the activity lifecycle docs, for more info:
This is by design:
If an activity is paused or stopped, the system can drop it from memory either by asking it to finish (calling its finish() method), or simply killing its process. When the activity is opened again (after being finished or killed), it must be created all over.
See Activity Lifecycle. It's also why the Service class exists:
A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application.
It's not a typical scenario but when onCreate() is called when going back to that activity that means the Android OS kills it in the background.
Reason: Android is experiencing some memory shortage so killing some of the background task will be a must.
Is there any way to prevent that from happening?
No, you don't have a control over it, there are many reasons why its having a memory shortage e.g. other app installed that certain device is consuming more than expected. Although you can handle this use-case by storing the current information in onSaveInstanceState() and recovering the value from onCreate().
Calling finish() on ActivityB or pressing back will just destroy ActivityB.
ActivityA will not be completely rebuilt. This means it will not call onCreate method. It will just call onResume.
This is the normal behaviour.
However, on special situations, the system could destroy ActivityA (maybe because it needs memory to perform another task), so when you go back to it, the system will have to rebuild it.
To simulate this situation, there is a setting that you can check/uncheck, called "Don't keep activities".
If you have it checked, you will be simulating the situation explained above, it will always destroy the ActivityA as soon as it is not shown, and when you come back to it, the system will have to rebuild it calling onCreate.
To avoid OnDestory() and OnCreate() beeing called all the time when navigating between my main activity and some sub activities, I have set the singleTop option in my manifest. Unfortunatly this causes that the UI in my main activity is gone when returning from a sub activity. Do I really need to redraw my UI manually?
I am still wondering how to handle these basic navigation features. Is it unusual to perform application initialization tasks (e.g. start services) in OnCreate() of the main activity?
I must be missing something from your explanation I guess because the very basic point that you provided is not correct. When you launch another (sub) activity from your activity then your starting activity is not destroyed but it is stopped. So your onStart is called when you navigate back.
So maybe you can explain a little bit more the background of your requirements.
Use android:launchMode="singleTask" for your main activity so the system will not re-create it if you call it via Intent. You can also clear the stack and go back to your main activity by using
Intent intent = new Intent(SubActivity.this, MainActivity.class);
intentHome.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intentHome.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intentHome);
My app has a launcher activity that looks at the intent used to call it and calls one of many activities based on the intent (let's call the child activity B). The launcher activity also launches an AsyncTask to do some clean up in SharedPreferences in the background. Once that background task finishes, the launcher activity calls finish() to terminate itself.
If the background task is still not finished when activity B terminates, I want to avoid returning to the launcher activity. How can I do that?
I am thinking of using android:noHistory="true" in the definition of the activity in the manifest. However, the description of noHistory says:
"Whether or not the activity should be removed from the activity stack and finished (its finish() method called) when the user navigates away from it and it's no longer visible on screen". So I am afraid that the activity might be terminated before it finishes running its background task.
Is my background task guaranteed to be allowed to run to completion? Is there some better way to do this?
Make is simple. Start a background task in your application instance and clean-up preferences there. This will allow you to finish your "dispatcher" activity immediately after it started a next required activity.
Regarding excluding the activity from the back stack. There are two options. You can either define "dispatcher" activity with android:noHistory="true" in manifest file, or start "dispatcher" activity with FLAG_ACTIVITY_NO_HISTORY. Both options will exclude the activity from back stack.
Also, if "dispatcher" activity is in background, Android might decide to destroy it at any time. This might lead to unexpected results. With proposed soliton you have no such issue either.
The main activity in my app sometimes calls startActivityForResult, expecting a result that will tell it (the main activity) what information to display next. Looking at the documentation for the process lifecycle, it appears that while the selection activity is active, the main activity is considered a "background" activity and could possibly be killed.
So what happens when the selection activity completes? I see that my activity will be re-created and onCreate is called with the SaveInstance Bundle, but then what? Is onActivityResult then called just as if my main activity had never exited and been re-created?
Also, is there any way to force this behavior in a testing environment, since it should otherwise be a very rare occurrence?
Hint: log statements
The paused state as described in docs is:
If an activity has lost focus but is still visible (that is, a new
non-full-sized or transparent activity has focus on top of your
activity), it is paused. A paused activity is completely alive (it
maintains all state and member information and remains attached to the
window manager), but can be killed by the system in extreme low memory
situations.
That means, under normal circumstances , your main activity should just transfer the control to onActivityResult() when the selection activity completes.
However, docs also state that:
A background activity (an activity that is not visible to the user and
has been paused) is no longer critical, so the system may safely kill
its process to reclaim memory for other foreground or visible
processes. If its process needs to be killed, when the user navigates
back to the activity (making it visible on the screen again), its
onCreate(Bundle) method will be called with the savedInstanceState it
had previously supplied in onSaveInstanceState(Bundle) so that it can
restart itself in the same state as the user last left it.
In such cases, the main activity can be redrawn.
One important point to note is that the docs have never mentioned onActivityResult() as one of their lifecycle methods here
So, it might also be the case where android system treats a sub activity and parent activity (read startActivityforResult() and onActivityResult()) in the same manner as it treats an activity - dialog as stated here:
A visible activity (an activity that is visible to the user but not in
the foreground, such as one sitting behind a foreground dialog) is
considered extremely important and will not be killed unless that is
required to keep the foreground activity running.
The answer is basically "yes": The activity is recreated and the control flows through onCreate(), onActivityResult(), onStart(), and so on.
An activity is also destroyed if the user rotates the device, e.g. from portrait to landscape, unless the application did not explicitly prevent this behavior. So simply rotate the device (CTRL-F11 on the emulator) to test.
Suppose there are two activities A and B and Activity A calls Activity B through startOnActivityResult(intent,200) then your Activity goes to background and Activity B is called (onCreate,onStart,onResume) depends on what you have overridden.
Whenever your B activity calls finish() then your Activity B is destroyed and Activity A comes to foreground. In this case now ie Activity A the call will be onActivityResult -> onStart -> onResume but your onCreate will not be called as it is only called when you call a certain Activity.
Suppose you have not called finish() from activity B and called Activity A through intent then only you onCreate() will be called.
Also onActivityResult() is very useful when you want to retain value of your spinners or you want to notifydatasetchanged() your ListView of your First activity after the event of Third activity. You just have to check your resultCode from the Activities in onActivityResult and perform your actions
My application has a main Activity A and that does a StartActivity on Activity B. If somebody uses a Task Killer (e.g., Advanced Task Killer), the application is killed but when they run the app again I see the Application object is being built (onCreate called) and then it goes right into Activity B not Activity A. The Manifest has A being the Launcher Activity.
I also see the scenario if I run A, then Activity B, bring down notification list and run Task Killer to kill my app, and press the Back key, it creates the Application object and then Activity B object.
Any ideas on how to prevent this behavior? Activity B assumes that Activity A has already run. I am able to kludge this but have a boolean in the Application object which is set on Activity A. In Activity B onCreate, if that global flag is not set, I do a finish(). Must be a better way to handle this since I have quite a few activities that would experience the same behavior.
Activity B should almost never assume any other Activity has run. Activities are meant to be stand alone units. If B must depend on A then there should be some test for a precondition and if it fails, opens ActivityA via an Intent.
Instead of keeping the flag in Application you may persist it in SharedPreferences - then your Activity B will always know the correct value of the flag.