Android startactivity and stacks keep in memory - android

we start activity and do not calling finish() on existing activity it keeps existing activity in stack and move to new activity if we press back button we return to previous activity.
Its mean all previous activities not beeing called finish() keep remain into the memory(Stack)
Now problem is i do not want to call finish for every activity is there any centralize place where i can define that keep only last 3 activities in stack and remove rest of them ?

In the Android Manifest in the [activity] tag you can specify android:noHistory - 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 —"true" if it should be finished, and "false" if not. The default value is "false".
A value of "true" means that the activity will not leave a historical trace. It will not remain in the activity stack for the task, so the user will not be able to return to it. This attribute was introduced in API Level 3.

When launching new Intents that resolve to Activities, consider setting appropriate Intent Flags, list of such flags can be found here. Using these flags, you can re-order activities on the history stack and clear it too. There is an excellent description of this in the Activity and Task guideline documentation see here.
Alternatively, in your deployment descriptor also known as Android Manifest, set appropriate attributes for your activity(noHistory would be a fit for your problem).
Refer this for details.

It sounds like you're worried about memory usage and you shouldn't be: Android handles all this for you.
When one of your Activities covered by another of your Activities so it is no longed visibile to the user it is stopped. A stopped Activity should still retain all its state but can be killed by the system when memory is needed. This is why you need to implement the onStop() and onRestart() methods so that your Activity can recover its state after being killed and restarted automatically by the system.
For more detail you can read about Component Lifecycles in the Androind Fundamentals document in the Android Developer documentation.

Related

Keeping object's state when user presses "Back" button

I have an app in which I programmatically create an EditText view. I assign an ID to that view using setId()
myEditText.setId(100);
so that Android automatically saves that object's state when pausing/stopping the app (as I was advised to do here). It works in these cases:
(1) When I leave the app using the "Home" button: if I then come back to the app, the object's state (displayed text) is restored, as expected.
(2) On a screen orientation change (which involves Android automatically destroying the activity and restoring it through a Bundle). The object state is also kept.
However, it doesn't work in this case:
(3) When I leave the app using the "Back" button: if I then come back to the app, the EditText object is empty.
Any explanation as to why this happens? Does Android really distinguish between leaving the app with "Home" and with "Back"? According to the documentation, the object's state should be automatically preserved, through a Bundle, even when the activity is destroyed. And that clearly happens in case (2). But not in case (3)!
If this is normal behaviour, how could I have the app's state automatically saved and restored when the user presses "Back"? I know I could use the SharedPreferences for that, but I'd rather have Android do that automatically, just as it does in cases (1) and (2).
This happens at least in Android 4.0 and 4.2 (I haven't tested others).
You really should study activity life cycles as there are many many ways to solve the problem. Since your activity is typically pulled off of the stack and destroyed when you navigate back one quick but not necessarily the best way is to make sure your activity flagged as singleTop or singleInstance in the manifest that way it is not pulled off of the stack and recreated when you navigate back and forth. You could also use the singleton Application class. Or pass the text back and forth as params. Or use a database. Or use MVC or some other programming paradigm that will allow your views to be destroyed and recreated with out the data populating them going with it. Lots of "or's". Study activity life cycles and then look at how you have your application architecture setup already and choose the method that will work best for you.
http://developer.android.com/training/basics/activity-lifecycle/index.html
http://developer.android.com/guide/components/tasks-and-back-stack.html
I think I found the explanation. I only needed to read the doc more carefully (thanks to #lentz for one of the links); see here and here:
When your activity is destroyed because the user presses Back or the activity finishes itself, the system's concept of that Activity instance is gone forever because the behavior indicates the activity is no longer needed.
If the user presses the Back button, the current activity is popped from the stack and destroyed. The previous activity in the stack is resumed. When an activity is destroyed, the system does not retain the activity's state.
The above explains behaviour (3) in my question.
However, if the system destroys the activity due to system constraints (rather than normal app behavior), then although the actual Activity instance is gone, the system remembers that it existed such that if the user navigates back to it, the system creates a new instance of the activity using a set of saved data that describes the state of the activity when it was destroyed. The saved data that the system uses to restore the previous state is called the "instance state" and is a collection of key-value pairs stored in a Bundle object.
The above probably explains behaviour (1) and (2).
What I don't see is why the user pressing Back should be interpreted as "the activity is no longer needed" ("its state needs not be preserved"). But that's a different matter.

Starting an Activity from Notification destroys Parent Activities

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

Activity is getting destroyed while pressing the home button

In my application, when I press the home button the activity is going to onDestroy(). It suppose to be called onPause() method only right?
Why it is happening so?
also check that you don't use the android:noHistory flag in your manifest for the Activity
documentation:
android:noHistory
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
It depends on how much memory your phone has, if your phone does not have very much memory, then it will destroy the activity to free up resources immediately. On new phones, this will not happen because they have plenty of spare memory.
You activity could be destroyed upon pressing the home button if the system is constrained and has determined it needs to free some resources. The documentation states that onDestroy() can be called if:
This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
Additionally, do note that the system can kill your program without calling onDestroy() after onStop() has been called. Therefore, any cleanup/data persistence code should be in either onPause() or onStop().
Well, it depends on a lot of factors. If you are facing this issue on Android 3.2+ devices, you should add screenSize property to android:configChanges
android:configChanges="keyboardHidden|orientation|screenSize"
Besides, also add android:launchMode="singleTop" to your launcher activity. Do note that you'd need to use Android SDK 15 or above as target, however, your app will work on older devices as well. Hope this helps.
another thing to check is whether your activity call finish() when onPause()
Of course may be memory problems, but before that check the manifest file, in the declaration of the activity, if you have "no history" declared (you don't want the activity to remain in the activity stack. Also you may using some flag when you create the activity with an intent.
Then, most probable answer is the one given by Alex Contour.

Pausing/Resuming Activity outside of an activity

I have 2 activities. Main Activity A & Activity B
I do not want Activity A to destroy. I am starting Activity B in a new task.
public static void startActivity(Class<?> startClass) {
Intent intent = new Intent(Constants.getActivity(), startClass);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Constants.getActivity().startActivity(intent);
}`
Constants.getActivity() returns the Context on current activity
startClass is the either activity "A" or activity "B"
Thing is they create/destroy the activities and they leak. Am I doing it wrong? How can I start activity "B" from activity "A" and vice versa keep them both in background when I dont need them.
First of all, what are you trying to do? You should always separate things you want to do in the background from your UI. Think of your Activities are simply a container to show the UI, everything else can be stored and restored from persistent storage or savedinstance bundles.
It is very crucial that you understand the difference between Activity lifecycle and Service lifecycle here.
I'm going to refer to my answer from another question here:
Your app will be in the background, onResume and onPause will both be called, provided that the OS have enough memory to keep the new app and all the old apps.
If you have a long running process that you need while the user not looking at it, use a service.
If you need the user to return the app in the same state, you need to do the work in onResume and onPause to save the state information and initialize your UI again when the user comes back. If you are really worried that it can get killed (well, it shouldn't lose the bundle I think), you can store them in SharePreferences for your app.
If you want to know when the app returns from that specific share intent, use startActivityForResult
You cannot keep an activity "alive" as you said. When an activity is paused, Android system is always able to claim its memory and unload it, at any time.
But if you want to switch from A to B, then maybe A and B can be different views inside a single activity. Maybe you'll want to have a look at http://developer.android.com/reference/android/widget/ViewFlipper.html
When you use tasks, cleanup is very important. You need to cleanup all tasks in the activity. readthis
If the activity does not have a lot of crazy initialization, just use finish and onCreates. Else be aware that onResume will be called often as you switch between activity's. Cleanup will be crucial here. If you dont cleanup, its possible one of your activities (with dead object reference from the other cleaned up activity) may come back up from the activity stack and throw exceptions. Its very difficult to debug this kinda exception.

App loses its ability to remember its stack when launched from another application

Now that I have researched this even more I am rewriting this to make it clearer. If you are looking for more info, there is some available in older edits.
What is happening:
(This refers to an application that has not set any launchMode
settings and so is using the defaults)
You launch an app from the Market or from the Installer. This
launches the root/main activity of the application with the
FLAG_ACTIVITY_NEW_TASK flag and no categories. Right now the
applications stack is [ A ]
Then you proceed to the next activity in the application. Now the
stack in this task is [ A > B ]
Then you press the home key and then relaunch the same application
by pressing it's icon from either the home screen or the app tray.
What is expected at this point is that activity B will show, since
that is where you left off. However A is shown and the tasks stack is
[ A > B > A ] This second instance of A is launched with the
following flags: FLAG_ACTIVITY_NEW_TASK,
FLAG_ACTIVITY_RESET_IF_NEEDED, and FLAG_ACTIVITY_BROUGHT_TO_FRONT. It
also has the android.intent.category.LAUNCHER category.
At this point, if you hit the back key, it will return you to B, as it
was when you left it.
Looking at the documentation it seems as if
FLAG_ACTIVITY_BROUGHT_TO_FRONT should only be set for activities that
use the singleTask or singleTop launchModes. However, this
application has not set any launchModes and is therefore using the
default standard launchMode.
I assume this is not suppose to happen in this case?
I should also note, that once it gets into this weird state, then it happens everytime the app is launched from the home screen or app tray. If the task is finished (restarting the
phone, force stopping the app, or hitting back all the way through the
stack) will fix this issue and will no longer launch it incorrectly.
It only happens if you launch the app from the installer or market and
then try to launch it from the launcher.
So in summary, why is this happening? Is there a way to prevent it?
Here is a workaround I have come up with so far. Some other workarounds I have seen involved looking at the currently running tasks. However, I really did not want to have to ask for another permission (GET_TASKS) from the user just to make a work around.
Please let me know if you see any holes in this.
In the main/root activity's onCreate method, check if the intent has
the FLAG_ACTIVITY_BROUGHT_TO_FRONT set and if so, call finish(). This
then pops the extra instance of A off the stack [ A > B > A ] becomes
[ A > B ] and from the users perspective, it launches into the
activity they were expecting.
It seems to work in all of my tests so far. My only worry is that if
there is some weird case where someones launcher would always flag a
launch with FLAG_ACTIVITY_BROUGHT_TO_FRONT even if the app wasn't
already in a task, and therefore would completely lock them out
because it would call finish() and not have anything in the stack to
return to.
--
As requested in the comments here is how you can check if an intent a specific flag:
int flags = intent.getFlags();
boolean hasFlag = flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT == Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT;
--
Also I should note that I am still seeing this problem occur sometimes with this fix in place. It doesn't seem to be a perfect solution.
Overriding of onConfigurationChanged() should help you to retain the state.
http://developer.android.com/reference/android/app/Activity.html
Configuration Changes
If the configuration of the device (as defined by the Resources.Configuration class) changes, then anything displaying a user interface will need to update to match that configuration. Because Activity is the primary mechanism for interacting with the user, it includes special support for handling configuration changes.
Unless you specify otherwise, a configuration change (such as a change in screen orientation, language, input devices, etc) will cause your current activity to be destroyed, going through the normal activity lifecycle process of onPause(), onStop(), and onDestroy() as appropriate. If the activity had been in the foreground or visible to the user, once onDestroy() is called in that instance then a new instance of the activity will be created, with whatever savedInstanceState the previous instance had generated from onSaveInstanceState(Bundle).
This is done because any application resource, including layout files, can change based on any configuration value. Thus the only safe way to handle a configuration change is to re-retrieve all resources, including layouts, drawables, and strings. Because activities must already know how to save their state and re-create themselves from that state, this is a convenient way to have an activity restart itself with a new configuration.
In some special cases, you may want to bypass restarting of your activity based on one or more types of configuration changes. This is done with the android:configChanges attribute in its manifest. For any types of configuration changes you say that you handle there, you will receive a call to your current activity's onConfigurationChanged(Configuration) method instead of being restarted. If a configuration change involves any that you do not handle, however, the activity will still be restarted and onConfigurationChanged(Configuration) will not be called."

Categories

Resources