I've read in the android docs that singleTop mode is this:
If an instance of the activity already exists at the top of the
current task, the system routes the intent to that instance through a
call to its onNewIntent() method, rather than creating a new instance
of the activity. The activity can be instantiated multiple times, each
instance can belong to different tasks, and one task can have multiple
instances (but only if the activity at the top of the back stack is
not an existing instance of the activity).
However, my app is behaving differently. My main activity has the singleTop launch mode defined in the manifest file. Here is where it's behaving oddly.
Start main activity from launcher.
From main activity, start sub activity.
When user presses back button (or actionbar home button), it sends intent to main activity with some extras. This means that main activity needs to be updated (depending on the user actions in sub activity.)
Main activity is shown with updated display.
-- the odd part is this --
From main activity, pressing back button goes back again to main activity.
Pressing back button a 2nd time brings up the launcher screen, then my app is put in the background.
On step 5, why does it bring up the main activity again? I thought singleTop will bring to front the main activity which is the current top of the stack in the task. But from that behavior in #5 and #6, it seems like it's creating two instances of main activity instead.
Is my understanding incorrect or something else is going on that I'm not clear of yet. Please help explain/clarify. Thanks.
My sub activity has its onBackPressed method overridden. And likewise, the main activity onNewIntent() handles the extras.
#Override
public void onBackPressed() {
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(MainActivity.UPDATE_ARG, true);
startActivity(intent);
super.onBackPressed();
}
Note: If I use singleTask mode, it behaves as I expected of singleTop. But I've read somewhere that singleTask and singleInstance are to be used sparingly.
From posted doc:
one task can have multiple instances (but only if the activity at the
top of the back stack is not an existing instance of the activity).
From your code:
When user presses back button (or actionbar home button), it sends
intent to main activity with some extras. This means that main
activity needs to be updated (depending on the user actions in sub
activity.)
when user presses back button your main activity dose not exist at the top of the current task and your sub activity is at the top because it has not destroyed yet, so it creates another main activity and do not use existing one because that main activity is not top.
look at this from the doc, note that the backstack contains current foreground activity:
why does it bring up the main activity again?
Well, because you're starting your activity again when you do:
startActivity(intent);
Any updates in your Activity should be performed in the onStart method (or onResume if applicable).
I've finally made sense out of all this (I think!). I'll explain.
android:launchMode attribute applies to the activity whether it's started from home launcher, from within your app (or from another app).
The intent flag Intent.FLAG_ACTIVITY_CLEAR_TOP is needed to implement the singleTop behavior. Therefore, I passed that flag when creating the intent prior to starting the activity.
For the main activity, here's what I did:
#Override
public void onBackPressed() {
Intent intent = new Intent(this, MainActivity.class);
// these flags are important!!
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(MainActivity.UPDATE_ARG, true);
startActivity(intent);
super.onBackPressed();
}
And correspondingly, I declared android:launchMode="singleTop" in the manifest file.
Related
When my android app is started, main activity is launched. It displays a full screen image for 5 seconds, and then it jumps to another activity using intent. What i want is to kill the main activity, so that when user presses the back button of navigation bar, instead of opening main activity, the app gets closed.
One more thing:- i don't want to keep on destroying previous activities. I just want to kill that one activity(namely main activity), just after the intent is sent to new activity, Because i will be adding more activities.
We can say that my true purpose is destruction of main activity, and making the next activity(out of all other activities) as a activity through which the app can be leaved using back button of navigation bar.
I am not able to properly explain my problem in words, but please try to figure out my problem what what all i have mentioned.
In your MainAcitivity ,call the second activity like this:
Intent intent=new Intent(this,<your second activity.class>;
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
I would add
android:noHistory="true"
to the AndroidManifest.xml, specifically in the MainActivity definition
To kill Activity you have to use method finish();
In MainActivity in code, where you are starting next activity add finish();:
Intent i = new Intent(MainActivity.this, NextActivity.class);
startActivity(i);
finish();
What you're trying to achieve is called a splash screen.
In your main activity start another activity and if the user presses back on another activity, simply call o finish on main activity. Destroying parent activities before child is sort of messy.
I'd recommend googling splash screens through cold app booting.
I want to keep a single instance of every Activity I start in my application. The launchMode singleTask was an option but it is working for only one Activity.
I want
to start an Activity if there is no instance and it is called.
and if any other instance of that Activity is present already then
that instance will brought to front without creating a new instance
of that Activity.
This property will be applied to more than one Activity.
No Activity does guarantee that it will be always on the top of the history stack.
My work until now:
I got many suggestions which are not valid for my case, so I want to point these out so that no other person would give the same suggestion.
I have set the launchMode to singleTop and this works only if the Activity is at the top of the history stack. onNewIntent() only gets called if Activity is at the top of history stack. and in my case the Activity may be at any position in stack. So this is not working.
When you launch an Activity, do it like this:
Intent intent = new Intent(this, MyActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
If an instance of this Activity already exists, then it will be moved to the front. If an instance does NOT exist, a new instance will be created.
You can set the android:launchMode of your activity to singleTop
In this case the if the activity already exists, new intents will bring it to front will be delivered to the activity's onNewIntent()
http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
This will work if your activity is on the top of the stack.
if you want to have a single instance of the activity, then you can set your launchMode to singleTask, but this is not recommended as it will make your activity reside in a separate task , which can be confusing to the users.
Use singleTop launch mode instead (docs): if there already is an Activity instance with the same type at the top of stack in the caller Task, there would not be any new Activity created, instead an Intent will be sent to an existed Activity instance through onNewIntent() method.
See can also this article for details on launch modes.
I've been testing the intent flags but I need to clarify something. I have two items in my navigation drawer and on click I do this,
Intent intent = new Intent(this, activityClazz);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
which classes are activities with same navigation drawers. -No fragment is used for various reasons-. In those activities I have buttons which open same activities but without the intent flags. What I wanted to do is to navigate activities with default Android behavior but also stack them in different stacks according to navigation items, like a tab usage.
Test case:
startActivity without the clear-new flag
startActivity with the clear-new flag
back
I expect to return to the first activity since I started the second one with a new task, so the first one should have stayed in the first stack) but I found out that the first one already destroyed.
The first activity (the one started without the flags) is destroyed because the flag combination for your second activity does the following:
FLAG_ACTIVITY_NEW_TASK: Start the activity in a new task OR if the activity already exists bring its task to the foreground. In our case, it does not exist yet. If you would only use this flag, then you would have task1 with activity1 and task2 with activity two. If you not hit the back button, task2 and activity 2 are dismissed and you return back to task1 and activity1.
FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_CLEAR_TASK: The clear task flag now enforces that if a task is brought to the front by new task then it is first cleaned (activities are finished). Citing the documentation:
If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. That is, the activity becomes the new root of an otherwise empty task, and any old activities are finished. This can only be used in conjunction with FLAG_ACTIVITY_NEW_TASK.
In conjunction, this means that with the back button you bring task1 with activity1 to the front, BUT the clear flag immediately finishes activity1. So this is why you encounter activity1 as being finished already.
I have an application which currently launches a simple LaunchActivity upon starting. Within this activity, there is a conditional in onCreate() to check for the existence of session data. If no session data exists, it starts the LoginActivity. Otherwise, it starts the MainActivity. In both cases, it finishes the LaunchActivity before starting either activity.
Using this approach, there is a brief flicker of the LaunchActivity before the start of either other activity. If this is an appropriate approach, what can be done to eliminate the flicker?
Is there another approach to this behavior which does not involve a LaunchActivity?
it finishes the LaunchActivity before starting either activity.
This sounds like you are destroying your Activity, then launching a new one. What you can do instead is open the new Activity using Intent then finish the launch Activity:
Intent intent = new Intent(this, MainActivity.class);//or LoginActivity.class
startActivity(intent);
finish();
Additionally, you can specify in your manifest that you do not want the launch activity to be included in the Back Stack. This will make it so that when the back button is pressed to exit the main or login activities, the launch activity will not be shown.
android:noHistory="true"
I have an app that starts a sequence of dialog-themed activities and I want to be able to pop them all off at once and go back to the main activity. I looked over existing questions like:
How to clear current activities in the stack?
how to kill sub activities and bring activity to top of stack
Android Popping off the Activity Stack
And based on that came up with this:
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
This works functionally, but the problem I have is that when this is executed, the screen behind the dialog-themed activity turns black for a second before finally animating the dialogs off the screen. If I pop these activities manually with a back button this does not happen.
In LogCat I can see that when I pop the dialogs using the Intent method above, the main activity is destroyed and re-created, whereas when I just use the back button, the onDestroy and onCreate methods do not run. Is there any way to prevent the main activity from being explicitly re-started this way?
You could just add singleTop to your main activity.
Here, read about it. It brings the existing instance of the activity rather than create a new one.
http://developer.android.com/guide/topics/manifest/activity-element.html
http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_SINGLE_TOP
What about if you, when you add your main activity to the backstack you add it with a tag other than null like:
transaction.addToBackStack("welcome");
And then you can just pop the backstack like such:
FragmentManager fm = getFragmentManager();
fm.popBackStack("welcome", FragmentManager.POP_BACK_STACK_INCLUSIVE);