Will android:alwaysRetainTaskState flag save the activity intent? - android

Suppose the current task stack of my app P contains activities: A B. A started B with some intent i.
A is defined with android:alwaysRetainTaskState flag.
Then user switched to other app, and after a while the process of P is killed by OS.
Then user started P from home screen. Since A has android:alwaysRetainTaskState flag, the stack will be restored to A B, and B is visible. My understanding is that, only B.onCreate() will be called and A.onCreate() will not be called. Am I right?
Besides, at the moment, does B still have the intent i? That is, when B calls getIntent(), will getIntent() returns null or an intent object, i?
Thanks!

My understanding is that, only B.onCreate() will be called and A.onCreate() will not be called. Am I right?
Yes, you are.
Besides, at the moment, does B still have the intent i? That is, when B calls getIntent(), will getIntent() returns null or an intent object, i?
getIntent() will work as always - it will return Intent object equal to one you have passed from activity A (not the same instance, but deserialized one)
This answer comes from my experiments (with android 2.3), but it fits neatly into Android's ideology of independent activities (IMHO it's the only reason why Intent can contain only serializable data even when it's used within one application), so I believe it's true for all android versions.
And "alwaysRetainTaskState" isn't even necessary - system will lead you to activity B even with default "false" value if you return to you task quickly (according to http://developer.android.com/guide/topics/manifest/activity-element.html#always, system will only reset task state "if the user hasn't visited the task for a certain amount of time, such as 30 minutes").

Related

Intent extras contains information even when activty is destroyed and relaunched

My application is launched using a tag, and based on the information contained in tag, it further proceeds. Now my app can also be started by using touching icon, and later it asks user to touch the tag. Small flow would be as below.
So MainActivity may contains tag data(if started from TagProcessorActivity), or may not contain data (if started from icon launch). Data is passed as intent extra value from TagProcessorActivity to IconLaunchActivity then to MainActivity. After main activity, app operation proceeds. When I leave the main activity, all my previous activities gets finish. I have checked onDestroy() is called for each activity. Now if I logout after MainActivity, (Logout simply a feature that closes all existing activity), and relaunch my application from recent app, my tag details still appears in MainActivity, which I dont know why.
To make is more clear my questions are:
1) Why activity which was destroyed still contains the information from previous launch.
2) I know about removeExtra() method, but is there some better options to tackle this problem.
3) and none the less, is there some thing wrong in my code or android is keeping that instance of intent extra?
PS: Not clear which piece of code to post, so if required feel free to ask for code.
Applications never exit in Android. onDestroy only destroys the activity, not any static variables left in the app. These will keep their value the next time an Activity is launched. This can be combined with some other features (like launching from the recent tasks menu causing you to launch the same intent) and this is the behavior you will get. The answer I always used was to detect this case (by checking the intent, there's a field that says if this is a restart or fresh), and ignoring the intent extras if so.
A finished task launched from Recents (as opposed to home screen launcher icon) will receive the old Intent, including its Extras, Data, etc. There is a way to know that it was launched from Recents so you can handle the Intent appropriately.
protected boolean wasLaunchedFromRecents() {
return (getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY;
}
In my humble opinion, that flag is poorly named (other flags referencing the Recents list actually use that word, e.g. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS, FLAG_ACTIVITY_RETAIN_IN_RECENTS) and the documentation was never updated to reflect the fact that many popular Android devices have a dedicated button for Recents:
This flag is not normally set by application code, but set for you by the system if this activity is being launched from history (longpress home key).

Whats Intent lifecycle?

Say i have started activity A with new Intent(context,class) i thats has sensitive data in it, when is this intent gets destroyed? in particular, in what cases among the following would getIntent() in Activity A's code return the exact same intent i?
Press on the activity's task on android's task manager
App icon was clicked and the activity was recreated and brought to front
Ive tried it with my app, iand i get weird results... normally it doesnt get the same intent, but sometimes it seem that it does, so i am not sure whats going on, anyway If i can be returned from any of the upper options how to avoid it?
I think a glance on lifecycle of an Intent would be helpfull if any1 know of any documentation regarding this...
Say i have started activity A with new Intent(context,class) i that's has sensitive data in it, when is this intent gets destroyed?
as long as there's object/class that holds reference to your Intent object - it will not be garbage collected. the Activity (Activity A) holds reference to the intent that started it, so as long as Activity A object is not garbage collected - then i also won't be garbage collected.
important comment: onDestroy() activity callback and class distractor are to different things!!!
in what cases among the following would getIntent() in Activity A's code return the exact same intent i?
assuming you are not calling setIntent() explicitly:
1) Press on the activity's task on android's task manager:
if the activity was previously stopped in reaction to back button navigation or someone called finish() explicitly on it, then the activity passed on the onDestroy() callback. in that case - pressing on the "application" from the recent tasks manager would re-created the activity with a new intent from scratch, and thus - getIntent() would bring this new intent that don't contain your extras or other overloads.
otherwise (the activity was sent to background via home button, or other activity started on top of it) : when you'll launch it back from the recent task - it will be intent object with the original extras you passed it before...
2) App icon was clicked and the activity was recreated and brought to
front
basically the same cases I mentioned in (1) apply to (2) , but basically it depends on two more things:
the intent flags that the specific launcher you are using is overloading on the intent it creates when it launch your activity.
the launch mode and activity flags you overloaded on the intent that you used to start your own activity.
assuming you are not using any of the above, and you are using normal good functional launcher application - the behavior would be exactly as I explained in (1)

Android application's initial activity is not the launcher designated activity when re-entering the app with the back button

I ran into a similar issue with the recent list in that there seem to a handful of conditions where an app will be completely destroyed but some other process will launch the app cold from the last activity that was being used. Since my app has a state that is built up over several designated activities I need to prevent this (i.e. null refs from onCreate()).
Without checking for state is all my onCreate() functions is there a way to just prevent this?
Also, other than the launcher, recents, the back button from other apps - are there more conditions where another thing can launch my app if I have not giving manifest permission to launch it explicitly with an intent?
Thanks!
If I understand this correctly, you have initializations in activity B that rely on activity A having passed them in. If an intent launches activity B first, without it being active, or being launched by A first, your activity will crash.
Easiest solution I can come up with is make your activity A (I assume your main activity) the broadcast listener for all the intents you wish to handle, and based off the intent action, dispatch to the appropriate child activities (B, C, whatever). That way activity A does all your initialization, and you can still launch into the appropriate activity to handle the original intent you wanted to.
Alternatively. If you detect your children activities are in an invalid state, you could put initialization into a parent activity that all your activities extend from. That way you should be able to initialize properly if the activity is a fresh launch. I'm not really a fan of this, I prefer making sure my activities are dependency injected with appropriate data.

Android main activity destroy(finish) automatically

In my App there is three activities: A, B, and C. Activity A is the main activity.
When I start Activity B from A using Intent, A is automatically destroyed. However, I am not finished with A when I start B. Then, when I press the back button in the device the A is started using onCreate and I've lost all my data since I am not using an Intent to go back.
The same happens when opening C from B.
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
startActivity(new Intent(ActivityA.this,
ActivityB.class));
}
});
What's going on? How do I fix this?
This was a mistake by me due to this the Activities were automatically destroying. I Checked the option under Setting=>Developer Option=>Don't Keep Activities. Due to that destroyed every activity as soon as the user leave it.
By Unchecked this option my app working fine.
If you are using 'Activity B' to get some sort of one-off result then it sounds like you need to be using the startActivityForResult construct. See [the docs](http://developer.android.com/reference/android/app/Activity.html#startActivityForResult(android.content.Intent, int))
However, to maintain state information about 'Activity A' without persisting it anywhere you want to be bundling all the information (fields the user has filled in etc.) into the Intent bundle passed to 'Activity B'. This bundle is delivered to 'Activity B's onCreate (and a few other lifecycle points) where you can continue populating any pertinent information from 'Activity B' and writing that information back to the intent bundle before restarting 'Activity A' with the modd'ed bundle when you are done with 'Activity B'. But here be dragons. This specific mechanism is employed in our app with a strict (wrong?) control over the back-stack. Specifically our 'Activity A' has the special manifest declaration of android:noHistory="true". This means that we also control what happens when the back button is pressed by overriding onBackPressed() at each activity and sending that same bundle through to a new instance of the activity we just came from. It looks like a normal back stack but since we are wanting to remember user input without persisting that information anywhere then it's a usable solution.
This allows for a wizard like input with each stage of the wizard input being it's own activity and only validated and correct information being persisted at the end.
An alternative would be to temporarily stored 'Activity A's data in the SharedPreferences area so that on restarting Activity A you can pull out the appropriate bits reassembling the original state of 'Actvity A' when you left it. Rest assured there is very little you can do when Android wants to kill your Activity A but you can accommodate it's very reasonable killing with the approaches outlined here.
Maybe it is not you that is destroying your activity.
From the page about Activity Life cycle: (Emphasis mine)
If an activity is paused or stopped, the system can drop the activity
from memory by either asking it to finish, or simply killing its
process. When it is displayed again to the user, it must be completely
restarted and restored to its previous state.
There explicit says that the system can kill your activity process.
Some possibilities is your device is low on memory, or your activities is memory hungry, making the system kill it.
Edit
In order to maintain your data, between the activities even if it gets destroyed. One way is to use the Application class, check this answer on Using the Android Application class to persist data, maybe that's what you're looking for.

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.

Categories

Resources