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.
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.
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.
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.
So I have two activites where I can switch between. Let's call them ActivityA and ActivityB.
Now if I'm in ActivityB and it somehow crashes and I start my App again it should appear the ActivityB and not A.
I thought of SharedPreferences(I already used it for the switching) and savedInstanceState, but can the last one handle with the savedInstanceState of other activites or just by its own?
Can I somehow tell ActivityA to look if there is already an instance of ActivityB and if so ro start it immediately?
When an app starts, Android always runs whichever activity it is told to (as defined in the manifest) - which can work to your advantage. You should be able to create a splash activity that determines what the last activity was (via tracking, sharedPrefs or perhaps savedInstanceState - I haven't mucked with the latter much), and then launch the appropriate activity before finish();-ing the splash activity.
Make sure the splash looks decent though - add in a handler that will keep it up for at least 1500-2000ms.
I have an app with 4 activities int the sequence say A->B->C->D and a service S that is started by A when the app is started. Now on a particular condition this service triggers a notification which again should start activity C withing my app and with the arguments that C usually needs from B. Also to function properly, C needs to use a static variable from the activity A. That was the setup.
Now what happens is when the notification is triggered from the service S and I click on it, activities A and B are automatically destroyed resulting in a force close(Since my activity C depends on a static variable in A). Why does this happen. I have used a TaskStackBuilder to place C's parent activity(i.e B) onto the stack so that normal back behavior takes me back to activity B.
Can anyone tell me the reason of this behavior. I do not want to run my Activity C as an interdependent task. I want it to be the same instance as that already in the app.
Please help me understand the problem here.
Activity should be independent. It is dangerous that activity C needs to use a static variable from the activity A. Although you create activities in order like A->B->C->D, Android may destroy A/B/C/D when your app is in background, and when user returns to your app, only activity D is recreated.
I encountered the same problem as you once, Starting an Activity from Notification destroys Parent Acitivities. This is because I used TaskStackBuilder. And even after I stop to use TaskStackBuilder, the problem remains. Only after I uninstall the app, it works as expected.
Check the comments for https://stackoverflow.com/a/28268331/1198666
This is happening because the Activity Lifecycle behaves differenty from ICS onwards. This fact answers this question, however I am yet to find out why this is happening. If someone wants to see the code and verify this behavior for themselves, HERE