I have a boot receiver which receives BOOT_COMPLETED event and launches the default activity for my application as follows:
if(MyApplication.GetCurrentActivity()==null)
{
Intent mActivityIntent = new Intent(context, LauncherActivity.class);
mActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(mActivityIntent);
}
I'm setting the activity after starting it. GetCurrentActivity() will return null if there are no activities launched or the last launched activity.
So far there is no problem.
But if the user touches the app icon before the LauncherActivity has been launched, two instances of the same activities are created as they are in two different tasks (I guess). How to prevent this and launch only one instance of the activity.
Try -
if(MyApplication.GetCurrentActivity()==null)
{
Intent mActivityIntent = new Intent(context, LauncherActivity.class);
mActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_NEW_TASK);
mActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(mActivityIntent);
finish();
}
UPDATE:
Then you can use FLAG_ACTIVITY_REORDER_TO_FRONT -
This flag will cause the launched activity to be brought to the front of its task's history stack if it is already running.-
if(MyApplication.GetCurrentActivity()==null)
{
Intent mActivityIntent = new Intent(context, LauncherActivity.class);
mActivityIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
startActivity(mActivityIntent);
finish();
}
For example -
Consider a task consisting of four activities: A, B, C, D. If D
calls startActivity() with an Intent that resolves to the component
of activity B, then B will be brought to the front of the history
stack, with this resulting order: A, C, D, B.
You can use:
<activity
android:name="name"
android:label="label"
android:launchMode="singleTop">
</activity>
This launch only one instance of the activity. Now, you can implement onNewIntent().
Hope it helps you :)
Related
I have few activities.For example A,B,C,D,E,F.
My Home screen is activity A.Now I start Activity B from that and C from Activity B.
So now my stack is A->B->C.
Now if I press back I should be able to navigate in reverse Order.
But If I start Activity D from C.
I want my stack to be A->D as I want to kill B and C.
My expectations is A is my Home screen which should be always there.B and C on having one task and D,E,F having other task.
There is one more catch - I can even start activity D->E->F from A and B from F. In that case when I start B from F, D,E,F should be removed from stack
There are several ways to accomplish this, depending on your application requireents. You should look at using startActivityForResult() in order to start one (or more) activities which can then return a result to the Activity that launched it. This may be a good solution for you.
The other alternative is to use your ActivityA as a kind of "dispatcher. In this case, when C wants to launch D but also clear the task stack back to A first, you can do something like this in C:
Intent intent = new Intent(this, ActivityA.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("launchActivity", "ActivityD");
Using the flags CLEAR_TOP and SINGLE_TOP will cause all activities on top of the existing instance of ActivityA to be finished and cause the Intent to be routed to onNewIntent() of the existing instance of ActivityA.
Now, in ActivityA, override onNewIntent() with something like this:
if (intent.hasExtra("launchActivity)) {
if (intent.getExtra("launchActivity").equals("ActivityD")) {
Intent launchIntent = new Intent(this, ActivityD.class);
startActivity(launchIntent);
} else ...
}
Let's say I have activities:
First ----------------- Open
A -> B -> C -> D -> E -> F
I want to call finish on activities C,D,E when F is opened, leaving A, B in the back stack such that when a user hits back from F they arrive at B, and so forth.
I have seen tons of examples of clearing the back stack, or pulling one activity from the back stack and clearing the rest, but every time I try to close a Task I end up with an empty back stack and the back button falls out of the app. I wish there were more info on this specific case, and what the best practice for this is (C,D,E,F is a workflow with API side effects that should not be re-entered once leaving, but falling out of the app on back pressed is also not what I want.)
One option is using startActivityForResult() from B, so C will be opened. Then open the next Activities using FLAG_ACTIVITY_FORWARD_RESULT until you reach F.
Override onBackPressed() in F to call setResult(), so users will go back to B. If you don't call startActivityForResult() again, the user will never again be able to reach Activitys C to F.
You can find a detailed example for using FLAG_ACTIVITY_FORWARD_RESULT in my
answer to another SO post
Suppose you have following A->B->C->D->E activities and when you backpressed from activity E, you does'nt want to see activities C & D.
Then you've to pass intent A to B by using this,
Intent i=new Intent(A.this,B.class);
startActivity(i);
Then you've to pass intent B to C by using this,
Intent i=new Intent(B.this,C.class);
startActivity(i);
Then you've to pass intent C to D by using this,
Intent i=new Intent(C.this,D.class);
startActivity(i);
finish();
Then you've to pass intent D to E by using this,
Intent i=new Intent(D.this,E.class);
startActivity(i);
finish();
At final you get Activity E and after that when you backpressed from E ,you able to go at Activity B and after that A.
Thankyou Happy Coding
The best workaround I could find was flagging the final task with FLAG_ACTIVITY_TASK_ON_HOME which just happens to be the task that was in the backstack at the point of departure, in my case. This isn't exactly an answer to the question, but if you are trying to clear a volatile workflow from the backstack and you don't want the user to "fall out" of your app on backpress subsequently, this is a viable option. See thread on the topic here: Android - Clearing Navigation Backstack
Edit: This code below creates separate application instances which I just noticed; not sure if there is a way to prevent that.
The solution I came up with was using taskAffinity, which you set in the manifest xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="co.example.app">
<activity
android:name=".activities.SplashActivity"
android:launchMode="singleTop"
android:taskAffinity="#string/affinity_main">
</activity>
<activity
android:name=".activities.MainActivity"
android:launchMode="singleTop"
android:taskAffinity="#string/affinity_main">
</activity>
<activity
android:name=".activities.WorkflowStepOneActivity"
android:launchMode="singleTop"
android:taskAffinity="#string/affinity_main">
</activity>
<activity
android:name=".activities.WorkflowStepTwoActivity"
android:launchMode="singleTop"
android:taskAffinity="#string/affinity_workflow">
</activity>
<activity
android:name=".activities.WorkflowStepThreeActivity"
android:launchMode="singleTop"
android:taskAffinity="#string/affinity_workflow">
</activity>
<activity
android:name=".activities.LeaveWorkflowActivity"
android:launchMode="singleTop"
android:taskAffinity="#string/affinity_main">
</activity>
</manifest>
Starting the app the main affinity presumably collects any activities that are started in a task without a declared affinity, but when I want to start a new affinity for my workflow I add new task to the intent:
In MainActivity, or anywhere I call the workflow:
public void startWorkflow() {
Intent intent = new Intent(MainActivity.this,
WorkflowStepOneActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
In intermediate workflow steps we do nothing special:
public void startWorkflowTwo() {
Intent intent = new Intent(MainActivity.this,
LeaveWorkflowActivity.class);
startActivity(intent);
}
Finally, we call finish on the Affinity from our LAST workflow activity, after firing an intent for the post-workflow activity:
public void startWorkflowCompleted() {
Intent intent = new Intent(MainActivity.this,
WorkflowCompletedActivity.class);
startActivity(intent);
finishAffinity();
}
This means our stack will look like this:
SplashActivity -> MainActivity -> LeaveWorkflowActivity
I am having 3 activities. From the third activity, I need to come back to the 1st activity when a GUI button is clicked. I know I can click the "physical" back button 2 times to make this but that is not an option.
So, is there any way I can display the 1st activity, without creating a new instance? I can pass the 1st activity's instance to the third activity, no issue with that.
Use the FLAG_ACTIVITY_CLEAR_TOP in your intent.
From the documentation:
For example, consider a task consisting of the activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then C and D will be finished and B receive the given Intent, resulting in the stack now being: A, B.
To use:
Intent intent = new Intent(getBaseContext(), FirstActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Intent intent = new Intent(src_ctxt, dest.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
src_ctxt.startActivity(intent);
This should do it
I think you need to make your activity B singleInstance that if it's already create you don't want to create again, that is launch mode of the activity can be defined in manifest android:launchMode that defines how the activity will be instanciated.
in your case use android:launchMode="singleInstance"
or
You can use flag Intent.FLAG_ACTIVITY_NEW_TASK. If the activity is already running it will bring that to front instead of creating new activity.
So I have an abstract class extended through the entire app that overrides the back key to reorder Activity A to the front (With the flag).
So, it would be:
A > B > anywhere, and the back key should bring me back to A
I'm using the FLAG_ACTIVITY_CLEAR_TOP, but it is entirely refreshing A for some reason and I don't want that.
So: Flag_activity_clear_top is reloading the onCreate() rather than onResume(). What gives?
If you want the activity to just be brought to the top without restarting it set the launchMode of the activity to singleTop in the manifest. You will receive a call to onNewIntent when the activity is being brought to the top. onNewIntent is called before onResume. If you only want this behavior for the specific intent you can add the FLAG_ACTIVITY_SINGLE_TOP(in addition to FLAG_ACTIVITY_CLEAR_TOP) to the intent with the addFlags call instead of the manifest.
Intent intent = new Intent(CurrentActivity.this, ActivityNeedOnTop.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
CurrentActivity.this.finish();
From the API docs for FLAG_ACTIVITY_CLEAR_TOP
For example, consider a task consisting of the activities:
A, B, C, D. If D calls startActivity() with an Intent that
resolves to the component of activity B, then C and D
will be finished and B receive the given Intent,
resulting in the stack now being: A, B.
**The currently running instance of activity B in the above example
will either receive the new intent you are starting here in its
onNewIntent() method, or be itself finished and restarted with the new intent.**
So I think your activity is itself finished and restarted.
I think I've just found a really strange bug... But it can just be somekind of feature that I never heard of.
On my application if I have any Activity on the AndroidManifest with android:launchMode="singleInstance" when you try to "clean" the stack to a certain point with the following code:
Intent intent = new Intent(this, Xpto.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
It goes to that activity. But when you press back, it returns to the previous.that should have been finished...
Example:
A -> B -> C
Then from C I call A with Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP having A singleInstance on the Manifest. It goes to A but it only brings it to front. And does not finishes C and B.
Can somebody explain this behaviour?
The Xpto class I'm calling is at the time the root activity of the stack.
from reading this thread:
http://groups.google.com/group/android-developers/browse_thread/thread/5eb400434e2c35f4
it seems that:
"The currently running instance of activity B in the above example will
either receive the new intent you are starting here in its onNewIntent()
method, or be itself finished and restarted with the new intent. If it
has declared its launch mode to be "multiple" (the default) and you have
not set FLAG_ACTIVITY_SINGLE_TOP in the same intent, then it will be
finished and re-created; for all other launch modes or if
FLAG_ACTIVITY_SINGLE_TOP is set then this Intent will be delivered to
the current instance's onNewIntent(). "
which means that you need to set your launchMode to multiple instance, and use only FLAG_ACTIVITY_CLEAR_TOP.
Intent intent = new Intent(this, Xpto.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
In the scenario you described, activity's B and C are not finished when you start activity A (which is the root activity). The documentation describes that with launch mode of singleInstance and the flag FLAG_ACTIVITY_SINGLE_TOP set, activities B and C will NOT be finished. If you want to have activities B and C finished, then you must set the launch mode to multiple instance and NOT set the flag FLAG_ACTIVITY_SINGLE_TOP.