from : http://developer.android.com/guide/topics/manifest/activity-element.html
android:relinquishTaskIdentity
Whether or not the activity relinquishes its task identifiers to an
activity above it in the task stack. A task whose root activity has
this attribute set to "true" replaces the base Intent with that of the
next activity in the task.
What is base intent here?
The base intent is the root intent that initially launched your app.
Most common one is probably the one that any app has when responding to the touch on the app icon. The LAUNCHER intent.
But it can be a custom one, for example, when you respond to custom scheme/url. But here is the trick and how relinquishTaskIdentity can be useful :
Say you start your app with the launcher icon. Your base intent is now the default one.
Now, say your app is completely killed (or you've backed with the hardware icon until your app closes) and you use a custom scheme/url to open your app, at this point the base intent is not the default one. It's the one generated from the scheme/url you clicked on and may contain custom data also. Now if you just close your app with the home button and reopen it, you will just resume where you were at. But if you back, back, back... with the hardware button until your app closes there is the trick : reopening it from the recent apps/multitasking view will reuse the base intent to open it and in this particular case it will still be your custom scheme/url intent and this can be very annoying.
Why annoying? Say the scheme/url your user clicked on was used to auto login and he succeeded: you don't really want to process this url/intent again just because your user backed up until its app closed and reopened it via recent apps/multitasking view, right?
Use relinquishTaskIdentity! This is very dependent to your setup and how your app is configured as for the Activities versus Fragments, but here is an example:
In the particular case I mentioned with the auto login via a link you could have an Activity that is dedicated and is only responding to scheme/url. This same activity should be different than the one flagged as LAUNCHER. and using the property relinquishTaskIdentity="true" on it will make the base intent become any subsequently shown activity via that one.
So what's the benefit in our case? The user can't enter the app with a custom scheme/url generated intent anymore unless he/she really clicked on one supported by your app.
Related
My Android app has a class called ListQuotes, which, as implied by the name, displays a list of quotes. It can be opened in three instances :
by selecting an individual from a list to see his quotes
by clicking the "Favourites quotes" button on the toolbar
by selecting a category from a menu ("quotes about love", "quotes about friendship", etc...)
Everytime the class is launched, the app checks the Intent to determine where it came from and to display the appropriate list.
I set up its launch mode as singleTop so that the app doesn't try to reload the class when I press the back button and that the intent is preserved.
However, by doing so, I cannot load the favourites from the toolbar if ListQuotes is already the foreground activity. In other words, if I select an author to display his quotes, and then click on the favourites button, it doesn't do anything.
Is there a way to make it so that the launch mode of an activity stays in singleTop, but that you force the app to open a new instance of the activity in a specific case ? Or, perhaps, to have the launch mode as standard, but have a way to recover a previous intent? Or should I just make a separate activity for my favourites ?
I hope this was clear, I haven't programmed in a long while, so it's possible I'm missing something. Thanks in advance.
Remove the singleTop launch mode. This will allow you to create another instance. Your statement:
I set up its launch mode as singleTop so that the app doesn't try to
reload the class when I press the back button and that the intent is
preserved.
makes no sense, as pressing BACK will not cause this strangeness.
I'm working on android app that lets users switch to google navigation.
I've been asked to get users a solution to get back to the app without scrolling through list of open apps. I found the way to draw a button on top of everything but am struggling to get nice flow with activity life-cycle.
If user gets back to the app through manually selecting my app in list of existing apps - my app starts with onResume,
However if i force my app to get back via service button it is starting with onCreate and all unsaved data i had withing my activity is getting lost.
This is the code i use to call activity back via service and button
Intent myIntent = new Intent ( getApplicationContext(), PhoneView.class );
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
myIntent.addFlags(Intent.FLAG_FROM_BACKGROUND);
getApplicationContext().startActivity(myIntent);
I think i can putExtra bool in this call from Service and before i let user off my activity - i can save all the fields and recreate it back, but it feels like to much of extra work..
Is there a way to call my app from service and have it use existing activity, rather than to go through onCreate again assuming i know that my activity is running?
I am building an Android app, which starts a service that keeps running in the background. When the user uses the Home button to close one of the activities (which communicate with the service), and then navigates to the app again, they get the last activity. This is correct behaviour.
However, when I explicitly stop the service (via an option in the menu), the app should "Quit". Currently, that works like this:
stopService(new Intent(this, MyService.class));
finish();
// just go to to the home screen, as it is intended in Android
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
and that works fine. But when I now navigate to the app again, it starts the previously opened Activity. What I want is that it starts the starting activity again (the launcher).
How could I accomplish that?
System.exit(0);
But you should have only one Activity in stack.
If you look at the description of android:excludeFromRecents it says:
Whether or not the task initiated by this activity should be excluded from the list of recently used applications ("recent apps").
isn't this what you are looking for ? Once the user hits exit, this app won't be in the recently used apps and hence will be completely removed from memory ? :)
I think that removing 'the app completely from memory on exit' is not the issue. Even if you stop your service the process is likely to remain in memory - that is the systems' decision.
You want an explicit, custom behaviour - user chooses your 'exit' option from menu --> next app launch starts at main activity - so you will need to handle this explicitly.
The default behaviour is that the user returns to their last activity when they re-launch. So they only return to the main activity if they exit by 'backing out' through your activities. Your use of an 'exit' menu option is non-standard (not to say it is bad).
One option would be to do the backing out through your activities yourself. Perhaps now you are just finishing the current activity and you should instead finish all the activities in the back stack.
Another option is that you could save a flag, and when the UI is launched again you could read that flag and launch the appropriate activity (but again be careful with the backstack). The easiest way to set that flag is probably by overriding onSaveInstanceState(Bundle) and then reading the bundle in onCreate (or use sharedpreferences).
Have you tried setting the clearTaskOnLaunch to true for your main activity (in your manifest).
From the documentation:
When the value is "true", every time users start the task again, they are brought to its root activity regardless of what they were last doing in the task and regardless of whether they used the Back or Home button to leave it.
This seems to describe what you want to do. I have never tried this personally, but it seems worth investigating for your purpose.
I'm having some problems with understanding the activity stack and the behaviour of how it affects my app.
Upon clicking a button it starts an Intent which opens the browser. When I'm in the Browser and I press the home button I land onto the homescreen. Now if I start my app again via launcher it opens the browser instead of my app. How can I circumvent opening the browser upon launching my app?
Right now, the code to open an url looks like this:
private void openUrlExternal(String url) {
Intent openUrlIntent = new Intent(Intent.ACTION_VIEW);
openUrlIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
openUrlIntent.setData(Uri.parse(url));
startActivity(openUrlIntent);
}
Am I using the wrong flags? If so, what flags do I have to use?
Thanks in advance!
Try like this:
openUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
openUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
That should disassociate the browser task from your own which means when you re-launch yours it should go to your Activity instead of the browser.
However it also depends on where you are calling openUrlExternal() from. If you call this when your activity launches it is still going to take you back to the browser, but if you call this from an event listener (i.e. Button click) then it shouldn't get called when you re-launch your app.
I don't think the accepted answer is exactly correct. It depends on what you intend (no pun intended, heh) to do.
Using Intent.FLAG_ACTIVITY_NEW_TASK it means that the launched activity is completely separate from the launching one. In particular, you can switch to the old activity with the Apps button without exiting the new one.
Using Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET means that the user will be returned to the previous activity when it's launched from the apps drawer.
In both cases launching the app again will get you to the previous activity. The main difference will be whether both activities (or just the last one) are shown in the app switcher.
I'm encountering the following scenario in my application:
Installing it and immediately opening it (using the open button
after the installation, instead of the icon in the applications
list).
Navigating through a few activities.
Clicking the home button.
Clicking the application icon to load it again.
Instead of returning to the activity I was in, the initial activity
is loaded. The previous activity is still there and can be accessed by clicking the back button, but there isn't really a way to know that and it looks like the app was completely restarted.
This may be an issue in this app, because in some cases it might require a registration after performing a few actions, and losing the focus on the activity could be very annoying
Is there anything that can be done to avoid that?
There's a couple of flags under Intent that might be helpful. You use them when an Activity is launched:
"FLAG_ACTIVITY_TASK_ON_HOME: If set in an Intent passed to Context.startActivity(), this flag will cause a newly launching task to be placed on top of the current home activity task (if there is one).
FLAG_ACTIVITY_REORDER_TO_FRONT: If set in an Intent passed to Context.startActivity(), this flag will cause the launched activity to be brought to the front of its task's history stack if it is already running."
http://developer.android.com/reference/android/content/Intent.html