Dean Solecki
Dean Solecki

Reputation: 173

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.)

Upvotes: 1

Views: 892

Answers (3)

Dean Solecki
Dean Solecki

Reputation: 173

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

Upvotes: 0

Vishal Yadav
Vishal Yadav

Reputation: 1024

  1. 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.
  2. Then you've to pass intent A to B by using this,

Intent i=new Intent(A.this,B.class);
startActivity(i);

  1. Then you've to pass intent B to C by using this,

Intent i=new Intent(B.this,C.class);
startActivity(i);

  1. Then you've to pass intent C to D by using this,

Intent i=new Intent(C.this,D.class);
startActivity(i);
finish();

  1. Then you've to pass intent D to E by using this,

Intent i=new Intent(D.this,E.class);
startActivity(i);
finish();

  1. 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

Upvotes: 0

B&#246; macht Blau
B&#246; macht Blau

Reputation: 13009

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

Upvotes: 1

Related Questions