I read the android developer guide and some articles in internet, I'm still confusing about the singleTask launchmode. Lets take an example:
User launch the App1, android starts a new task. Assume the App1 creates activities in follow order:
ActivityA -> ActivityB -> ActivityC
That's how task1 looks like.
Then user click the home buttom and choose to launch App2, so task1 goes in background and android start a new task: task2, user does something:
ActivityD -> ActivityE
now lets say ActivityE try to start ActivityB , and ActivityB has the launchmode singleTask.
What I understand is that task1 comes to frontend again and task2 goes to background. And task1 looks now like this:
ActivityA -> ActivityB
Which means:
The ActivityC will be removed from task1 and ActivityB becomes to the top Activity.
If user now click on "Back" button, he will come to ActivityA of task1 instead of back to ActivityE of task2
Am I right?
Thanks
You sound right.
Why don't you test it.
There is also this app that can help explain launch mode:
https://play.google.com/store/apps/details?id=com.novoda.demos.activitylaunchmode
Sources are at https://github.com/gnorsilva/Activities-LaunchMode-demo
The ActivityC will be removed from task1 and ActivityB becomes the top Activity.
Yes, you are Right...
ActivityC will be removed from i.e. the onDestroy method of the ActivityC will be called. Hence when the user launches Task 1 again, the ActivityB is shown rather than ActivityC.
Have created 2 Tasks (Projects) and uploaded the same # SendSpace. Try it out...
If you look at androids documentation it says
" A "singleTask" activity allows other activities to be part of its task. It's always at the root of its task, but other activities (necessarily "standard" and "singleTop" activities) can be launched into that task."
This means that when you click the home button all the activities above the single-task activity (which in your case is ActivityB) are removed from the stack.
In the sample, the app's I had given you earlier if you just run the project "AndroidTest" and click the home button in the logs you can see that the 2nd Activity is put on Pause, and when you launch it again from the "Recent App's" list the 2nd Activity is Destroyed.
In a scenario where the Activity's above the Single Instance activities (ActivityB) are not removed from the Back Stack, and another application request this Activity (ActivityB) it may not be shown and the intent may be dropped. But this has extremely fewer chances of happening because the user will have to press the Home button and but the current Task\App in the BackStack before he could navigate to another Task\App.
Hence the warning
The other modes — singleTask and singleInstance — are not appropriate for most applications, since they result in an interaction model that is likely to be unfamiliar to users and is very different from most other applications.
I hope this solves your doubts.
Correct, whenever singleTask activity is launched it comes foreground clearing all activities currently present above it, if your singleTask activity is on the top, it will behave same as singleTop.
P.S - onCreate is not called 2nd time, instead onNewIntent is called.
check this link, very well explained about launchmodes.
https://medium.com/android-news/android-activity-launch-mode-e0df1aa72242
Related
I want to prevent user from leaving my app. I am trying to achieve this through home launcher activity/application and I don't understand android's behaviour. Pressing HOME first time always creates new activity in new task instead of moving the existing one to the foreground. When pressing HOME second time etc, nothing happens. See example:
I have a Login activity (A) and Settings activity (B). B is opened from A. A is set to be a launcher (LAUNCHER, DEFAULT, HOME categories).
A opens B
task T1: A -> B
HOME
another A is created into a new task (why?):
T1: A -> B
T2: A
A opens B (task T2)
T1: A -> B
T2: A -> B
HOME
nothing happens, why?
I get the same behaviour when A's launchMode is either singleTop, singleTask or standard. With singleInstance there is only one A, but the B gets alone in T1 and I don't want that.
Why there is always a new task created? All intents flags have always the FLAG_ACTIVITY_NEW_TASK flag set. Why does android do that?
Is it the same behaviour as posted here or here? I can't use that solution because android creates a new task so A will always be the root. (or how can I check that this is a second instance?)
I can't use singleInstance as posted here, because I don't want B to be alone (if A is visible, it is also the only activity and task (login purposes)). I tried to remove all other tasks through ActivityManager but getAppTasks() is for SDK >= 21, my min is 16.
I can't even use this solution because I never get intent with FLAG_ACTIVITY_BROUGHT_TO_FRONT flag. There is always FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
I've tried a lot of combinations with launchMode, clearTaskOnLaunch, noHistory, ... but nothing successful - always new task.
Any idea how to solve this? Running on Lollipop. Thank you.
I create a child activity "B" from activity "A". if the user should leave the app for any reason (most likely hitting the home button), I would like activity "B" to end and the app to be at activity "A" once the user resumes.
If I call finish() manually, activity B ends and it returns to activity A. This is the behaviour I would like to happen when the user leaves the app.
I have tried to call finish() in the onPause(), onStop() and in the onUserLeavingHint() of activity B. In each case, this appears to work correctly, and I can see mParent.finishFromChild(this); being called inside activity B.
However, as soon as the user switches back to the app, the onCreate() of activity B gets called and the user ends up in activity B.
How can I ensure I end up in the parent activity when I call finish() from within an onStop() (or similar) handler?
UPDATE: It appears that the issue is related to activity B being declared as using a SingleInstance launch mode. Removing this feature seems to have resolved the issue. Changing this has introduced other issues that I have since managed to fix.
The reason for this happening is that Activity B is set as a SingleInstance Launch Mode. The reason it was set to this (by another developer) is somewhat related to the reason I had wished the activity was ended when the app is in the background - it was to ensure the user could not reach this activity by hitting back on any other activities subsequently dispatched from Activity B.
To resolve this. I first ensured no activities could be created from B. To instead return from B and pass any required Intents on to A. Simplifying the back stack. (Calling activity B with startActivityForResult() is one possible way of doing this.)
Now, the reason SingleInstance causes this issue to arise in this scenario, is because Activity B is launched in a seperate new task. When the user attempts to resume, they re-enter this single-activity task. The rest of the app is running in a seperate task. The only thing the task can reasonably be expected to do is relaunch the activity. When the user presses back, the only thing it can do from there is to close the task (and hence appear to exit the app). For the expected behaviour to occur the user would have had to have selected the other, first task (through a long click of the task list).
Hopefully this self-answer can help someone who has encountered a similar issue.
I need to launch an external activity (which isn't mine) for a split second, and then I have a service that launches my previous activity for the user to see.
This works great, but the problem is when the user then presses the back key, he gets to that external activity.
I have two different activity launches here, one for the external activity, and one for my activity to return to (in which I need to use FLAG_ACTIVITY_NEW_TASK because I'm launching it from a service).
For these two launches I've tried any combination of:
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET, FLAG_ACTIVITY_NO_HISTORY, FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_CLEAR_TOP, FLAG_ACTIVITY_CLEAR_TASK, FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS.
Nothing helps, I keep seeing the external activity after pressing back.
I've seen some similar questions here, but they all have the middle activity in their own app, so they can call finish on it, or set noHistory="true" in the manifest.
Any ideas?
UPDATE:
Seems like the issue is that I re-launch my previous activity from a service, which means I need to give it FLAG_ACTIVITY_NEW_TASK, from the documentation of Tasks and Back Stack:
FLAG_ACTIVITY_NEW_TASK Start the activity in a new task. If a task is
already running for the activity you are now starting, that task is
brought to the foreground with its last state restored and the
activity receives the new intent in onNewIntent(). This produces the
same behavior as the "singleTask" launchMode value, discussed in the
previous section.
And from the singleTask paragraph:
"singleTask" The system creates a new task and instantiates the activity at the root of the new task
...
Note: Although the activity starts in a
new task, the Back button still returns the user to the previous
activity.
So I need a flag that overrides this behavior somehow...
I have program with login, main activity and other activities.
First step is login activity(A). If login succeed start main activity(B) and call finish for (A).
working with (B) I'm calling some activities and then back to (B).
When decide to exit - I call logout and try to close (B) calling finish.
This logik works in 70% ot time :(
Unfortunately on 30% after calling finish for (B) - activity(A) appears on screen and start logging me.
Who is starting (B) again? I din't see relation between problem and program usage.
Update:
I put hohistory for (B) and start (B) with FLAG_ACTIVITY_CLEAR_TOP.
UPDATE2: Described behaviour is typical when I set screen orientation mode in code. In manifest is set portrait. When start activity I'm setting orientation depending on user config. This produced onCreaste twice. I got managed to handle this properly, but this causes problem as described. If I don't set orientation - one onCreate is called and no problem with finish.
Check the following links, you will get the solution:
Finish parent and current activity in Android
http://developer.android.com/guide/topics/manifest/activity-element.html#clear).You
You can try this when you logout in activity B. The activity displays the home screen.
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
Are you starting your application from an IDE (like eclipse), or from the app installer? If so, you will see this situation if you do the following.
Launch your application from the IDE or after installation from the installer (displays your first activity)
press the HOME key (takes you back to home screen)
launch your application again by selecting it from the list of available applications
This sequence will create 2 copies of your first activity, one on top of the other. When you finish the top one, the one underneath it will be shown.
You say this doesn't happen all the time. If you don't launch the app from the IDE, but just from the list of available applications you won't see this behaviour. Also, if you never press the HOME key and relaunch the app using the list of available applications you won't see this behaviour either.
When you go from activity A to activity B first time you are supposed to clear your stack top. Otherwise activity A stays in the stack below B and when u finish B, activity B is called again.
you should set in manifest file android:noHistory="true" to make your A activity not to stay on android stack.
In case you would like to do it from code in future by using intents Intent.FLAG_ACTIVITY_NO_HISTORY will do the job for you.. Cheers
Using setScreenOrientation made thinks complicated.
It is not enought to set noHistory for activityA and call activityB with FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_NEW_TASK.
When Start app in portrait mode /as declared in manifest/ - It was OK.
But when call setScreenOrientation - have to call finishB 2 times to exit.
/Probably because ot 2 times onCreate for activityB/.
This made thinks to work:
For activityA: android:noHistory="true" and android:launchMode="singleInstance" in manifest.
Start activityB with startActivityForResult and flags FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_NEW_TASK.
In activityA:
1. startActivityForResult(activityB)
2. finishA.
In activityB - when call finish() for B - because of 'singleinstance' system din't start activityA again.
Hope this help.
If anybody know reason which will cause error - please write me.
I have a widget which can pop up small dialogs when clicked. These dialogs are displayed by an activity called RemoteActivity in singleInstance launchMode. In one of these dialogs, there is a button to launch the main app MainActivity, which has the standard launchMode.
However, when this button is clicked, and startActivity() called, MainActivity isn't launched, although I can see the corresponding "Starting activity: Intent { ... }" in logcat.
If I set the launchMode of RemoteActivity to standard then MainActivity gets launched, but this isn't what I want, RemoteActivity is merely an extension of the widget, I don't want it to stack with any other activity.
I also tried with FLAG_ACTIVITY_NEW_TASK but it didn't help, and it shouldn't be necessary anyway according to the docs:
A "singleInstance" activity, on the
other hand, permits no other
activities to be part of its task.
It's the only activity in the task. If
it starts another activity, that
activity is assigned to a different
task — as if FLAG_ACTIVITY_NEW_TASK
was in the intent.
How can I launch my main activity?
UPDATE / ERRATA:
The MainActivity is actually launched but only if it isn't already part of a task. If I launch MainActivity normally through the launcher, and press Back to exit, then RemoteActivity does launch MainActivity.
But if, instead of pressing Back, I press Home to leave MainActivity, then RemoteActivity can't launch MainActivity, although the intent appears in logcat.
I'm testing this on Froyo.
Any idea of what's happening?
Maybe the noHistory flag will work for what you are looking for?
I found the problem: this behavior only occurs when calling finish() before startActivity() in RemoteActivity. If I call startActivity() before finish() then it works fine whether MainActivity is already part of an existing task or not.
Go figure...