Could an activity with single task flag be cleared via clear top? - android

Assume that I have a launcher activity A which has singleTask launch mode. Now imagine that A starts Activity B like;
Intent intent = new Intent(this, B.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivityForResult(intent, REQ_ACCOUNT_ACTIVITY);
In this case it seems like A's not destroyed. I wonder if it's correct or did I something wrong?

You can achieve this by using below attribute in AndroidMenifest file
android:finishOnTaskLaunch="true"
<application
...
>
<activity
android:finishOnTaskLaunch="true"
android:launchMode="singleTask"
...>
</activity>
</application>
If you not want to kept new activity in the history stack. Use below one_
FLAG_ACTIVITY_NO_HISTORY
//Actvity B is not in BackStack if we set FLAG_ACTIVITY_NO_HISTORY flag
Intent intent = new Intent(this, B.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivityForResult(intent, REQ_ACCOUNT_ACTIVITY);
As soon as the user navigates away from Activity B, the activity is finished. This may also be set with the noHistory attribute.
For more -> Tasks and Back Stack

It's been a while but I came across my own question when I was wandering over here.
The activity A was not getting deleted because the flags are set for the activity B. And when I call this code, there's no such activity called B in the task stack already. So effectively, nothing to clear on top of B.
Hope this helps.

Related

Should I use FLAG_ACTIVITY_CLEAR_TOP in this case? how to use FLAG_ACTIVITY_CLEAR_TOP intent flag?

In my app I have the following Activity flow:
LoginActivity > DashboardActivity > (if user opts to change their password) > ChangePasswordActivity
If the user successfully changes their password, I'd like to send them back to the very first Activity which is LoginActivity. I would like to pop DashboardActivity in the process to prevent any unwanted lingering Activities.
Is it correct to use FLAG_ACTIVITY_CLEAR_TOP to start a new LoginActivity in this case? I'd like to know which flags are appropriate in this scenario.
For what it's worth, my DashboardActivity has a launchMode set to singleTop in my AndroidManifest.
If you want to just clear the previous activities from stack and
launch login activity just do this
in manifest file your login activity should be like this
<activity
android:name=".LoginActivity"
android:screenOrientation="portrait"/>
After changing password launch the login activity with following tags
Intent intent = new Intent(ChangePassword.this, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
By setting flag to Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
all the previous activities will be cleared from stack.
for more info check this
https://developer.android.com/reference/android/content/Intent
From the official documentation - FLAG_ACTIVITY_CLEAR_TOP
If set, and the activity being launched is already running in the
current task, then instead of launching a new instance of that
activity, all of the other activities on top of it will be closed and
this Intent will be delivered to the (now on top) old activity as a
new Intent.
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.
LoginActivity > DashboardActivity > (if user opts to change their password) > ChangePasswordActivity
In order to clear task and intent to LoginActivty you should use
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Is it correct to use FLAG_ACTIVITY_CLEAR_TOP to start a new LoginActivity in this case? I'd like to know which flags are appropriate in this
FLAG_ACTIVITY_CLEAR_TOP will clear everything from the stack and make
the new activity as root task. In your case, there is no previous
activity for LoginActivity it will also work but not advisable.
For what it's worth, my DashboardActivity has a launchMode set to singleTop in my AndroidManifest.
It will not be useful in your case though you get detail of “LaunchMode" here https://blog.mindorks.com/android-activity-launchmode-explained-cbc6cf996802
Also check
https://blog.mindorks.com/android-task-and-back-stack-review-5017f2c18196
for details

How to close all activities in a task without clearing the entire backstack?

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

Single android application with two tasks and its navigation

I am developing a calling application. My HomeActivity is a singleTask activity. My call activity is also a singleTask activity.
From HomeActivity a call is initiated. At this moment, there are two tasks for my application as they both are singleTask. In call screen I have a button to reach my HomeActivity.
When I press the home button in my call screen and navigate back, my call activity is destroyed. But it should not get destroyed. It should remain.
When I press home button in call screen I do the below.
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setClass(this.getActivity(), MyHomeActivity.class);
startActivity(intent);
My manifest declaration:
<activity
android:name=".XXX.MyHomeActivity"
android:label="#string/app_name"
android:alwaysRetainTaskState="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustNothing"
android:theme="#style/MyTheme"
>
</activity>
<activity
android:name=".XXX.MyCallActivity"
android:label="#string/app_name"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="#style/MyTheme"
android:windowSoftInputMode="adjustResize">
Inflating HomeActivity from CallActivity:
Intent intent = new Intent();
intent.setClass(this.getActivity(), HomeActivity.class);
startActivity(intent);
Inflating CallActivity:
Intent intent = new Intent();
intent.setClass(this, CallActivity.class);
startActivity(intent);
Can anyone help me with the navigation parameters to use to achieve this?
In order to have 2 tasks, you need to make sure that the root Activity of the tasks have different taskAffinity, otherwise Android will put both in the same task. The default taskAffinity is the name of your package.
Add android:taskAffinity="" to one of the <activity> declarations.
According to the documentation using FLAG_ACTIVITY_CLEAR_TASK will do the following:
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.
So if want your CallActivity to stay in the back stack you can simply do this:
Intent intent = new Intent();
intent.setClass(this.getActivity(), MyHomeActivity.class);
startActivity(intent);

Resume the Activity instead of Starting if already exists in back stack

I have an Activity_1 after a lot of steps, say
Activity_2 > Activity_3 .... in some Activity_n I change some data related to Activity_1 and call it using
Intent intent = new Intent(Activity_n.this, Activity_1.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
To refresh the content. But later I can go all the way back to Activity_1 where I started, which has old data.
Instead I want the initial Activity_1' s onResume() to be called, using the above code. Or appropriate Flag
FLAG_ACTIVITY_CLEAR_TOP
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.
That' what the docs say, but not what I am getting.
You can add this two lines and try
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Write this in your manifest file inside Activity
<activity
android:name=".SettingsActivity"
android:launchMode="singleInstance"
android:screenOrientation="portrait" >
</activity>
"singleTask" and "singleInstance" activities can only begin a task. They are always at the root of the activity stack. Moreover, the device can hold only one instance of the activity at a time — only one such task.
You can use SingleTask or SingleInstance
"singleTask" - The system creates the activity at the root of a new task and routes the intent to it. However, if an instance of the activity already exists, the system routes the intent to existing instance through a call to its onNewIntent() method, rather than creating a new one.
"singleInstance" - Same as "singleTask", except that the system doesn't launch any other activities into the task holding the instance. The activity is always the single and only member of its task.
Refer this link http://developer.android.com/guide/topics/manifest/activity-element.html
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
Visit : http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_REORDER_TO_FRONT
Resume Activity from backstack if exists or create a new one if not
android:launchMode="singleTask"
add this line to your app's AndroidManifest.xml and start the activity with a normal Intent.

Android remove Activity from back stack

Okay so I'm kind of stumped on what to do with this. So I have the MainActivity, and from there an Activity can be launched to DegreePlanActivity, and from there another Activity can be launched to EditDegreePlan. I've got EditDegreePlan set to noHistory in the AndroidManifest. The problem is after they save the EditDegreePlan it launches an Activity to DegreePlan. So if the user presses Back they have to press it twice to get to MainActivity again. I want to get rid of that so they only have to press it once. I'm stumped on how to do this though.
If I set DegreePlanActivity to noHistory then they couldn't press Back to it while in EditDegreePlan.
I've tried overriding onBackPressed method and launching an intent to MainActivity. The problem then is that they have to press Back multiple times to exit the app then.
What should I do?
FLAG_ACTIVITY_CLEAR_TOP clears your Activity stack , you can use the code below:
Intent intent = new Intent(this, Activity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Remember that this flag clears just Intermediate Activities , for example if you have A,B,C in your Back Stack then going from C Activity to D with this flag this does not clear Back Stack and the Stack would be A,B,C,D but if you go from Activity D to Activity A with this flag , B,C,D Activities will pop up from the stack and you will have just A in the Back Stack .
To remove activity from back stack inside manifest add android:noHistory="true" to your activity inside the manifest file.
See sample below.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activity"
android:versionCode="1"
android:versionName="1.0">
<application android:name="MyApp" android:label="My Application">
<activity android:name=".LoginActivity"
android:noHistory="true"> //add this line to your activity inside manifest
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
simple solution for API >= 15 to API 23
user activity name in intent.
Intent nextScreen = new Intent(currentActivity.this, MainActivity.class);
nextScreen.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(nextScreen);
ActivityCompat.finishAffinity(currentActivity.this);
I would suggest that you use startActivityForResult(), instead of simply startActivity(), when you launch the EditDegreePlan-Activity, as described in the Android tutorials.
In the EditDegreePlan-Activity you then call
setResult(RESULT_OK);
finish();
If you don't expect any data from the EditDegreePlan-Activity, then you don't necessarily have to implement the onActivityResult.
It seems, that you will get the desired behavior if you do not specify any flags at all. The back button would just do the right thing. To get an activity closed from within your code use the finish() method it has the same effect as the user pressing the back button. So you will automatically arrive at DegreePlan when you finish the EditDegreePlan, no need to call any Intents either.
You can call finish before you start your new activity. This will remove the current activity from the stack, so when you press back button from the next activity, the first activity will not be called from the stack history.
Intent i = new Intent(MainActivity.this, NextActivity.class);
finish();
startActivity(i);
Here is your flow:
MainActivity --> DegreePlanActivty --> EditDegreePlan--> DegreePlan --> MainActivty
Override these method inside your "DegreePlan"
public void onBackPressed() {
super.onBackPressed();
Intent goToMainActivity = new Intent(getApplicationContext(), MainActivity.class);
goToMainActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // Will clear out your activity history stack till now
startActivity(goToMainActivity);
}
use this to clear the stack :
menuIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Intent intent = new Intent(getContext(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
You can add flags as follows and start Activity, try below code
Intent i = new Intent(activity, Payment.class);
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_TOP);
activity.startActivity(i);
This code should help you out: It is in Kotlin
private fun verifyIfUserIsLoggedIn(){
val uid = FirebaseAuth.getInstance().uid
if(uid== null){
val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK.or(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
}
}

Categories

Resources