Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Navigation Component Activity Intent Flags

I have created a navigation action from a fragment to an activity, but I have no way of clearing the back stack. When I execute the navigation action from my fragment to my new activity, and I press the back button, I am taken back to the previous activity and previous fragment. I have no way of setting Intent flags, using the navigation graph, to clear the previous activity from the back stack.

<fragment
    android:id="@+id/loginFragment"
    android:name="com.myapp.auth.LoginFragment"
    android:label="login_fragment"
    tools:layout="@layout/login_fragment" >
    <action
        android:id="@+id/action_loginFragment_to_webActivity"
        app:destination="@id/webActivity"
        app:popUpTo="@id/loginFragment"
        app:popUpToInclusive="true" />
</fragment>
<activity
    android:id="@+id/webActivity"
    android:name="com.myapp.web.WebActivity"
    android:label="activity_web"
    tools:layout="@layout/activity_web" >
</activity>

PopTo and Inclusive flags have no effect on the back button when navigating from a fragment to a new activity, even though they can be set in the graph editor. I am able to navigate, using the back button, to the previous activity that I no longer want in the stack.

Before migrating to the navigation graph, I could just specify this behavior with Intent flags:

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

How can I achieve the same thing with the navigation graph?

like image 971
Pop-A-Stash Avatar asked Jan 07 '20 17:01

Pop-A-Stash


2 Answers

Referencing Fatih's answer

val extras = ActivityNavigator.Extras.Builder()
        .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
        .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        .build()
findNavController().navigate(BlaBlaActivityDirections.actionFooBarToBlaBlaActivity(), extras)

Note You need to add these flags to the activity stack:

  1. FLAG_ACTIVITY_CLEAR_TASK: sets the activity as the root task. used with
  2. FLAG_ACTIVITY_NEW_TASK: treats the activity as launcher activity.
  3. FLAG_ACTIVITY_REORDER_TO_FRONT: brings the activity to front. Use this only if you have other activities on the stack and you don't want to clear it.
like image 174
abd3lraouf Avatar answered Sep 29 '22 12:09

abd3lraouf


I had to hack my way through the same problem. To solve this, the first thing you have to do is to create an action to navigate to the Activity, as you already had done.

For example:

<action
    android:id="@+id/action_frag_to_myActivity"
    app:destination="@id/myActivity"
    app:popUpTo="@id/myActivity" />

Now, you can pass arguments to the Activity as intent extras, so you can take advantage of that to make the destination Activity do the "dirty work" and clear the back stack for you.

Say that you have this Activity tag inside your navigation graph:

<activity
    android:id="@+id/myActivity"
    android:name="com.dummy.MyActivity"
    android:label="activity_my" />

You could add an argument in it and add a default value. For example:

 <activity
    android:id="@+id/myActivity"
    android:name="com.dummy.MyActivity"
    android:label="activity_my">

        <argument
            android:name="clearBackstack"
            app:argType="boolean"
            android:defaultValue="true" />

</activity>

Then once you call findNavController().navigate(R.id.myActivity) it'll pass an intent extra with the key "clearBackstack" which you can read inside the Activity onCreate() method. Something like the example below.

MyActivity.kt

private val EXTRA_LOGOUT = "clearBackstack"

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    if (intent.extras?.getBoolean(EXTRA_LOGOUT) == true) {
        clearBackstack()
    } else {
        setContentView(R.layout.activity_my)
    }
}

private fun clearBackstack() {
    startActivity(Intent(this, MyActivity::class.java).apply {
        addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
    })

    finish()
}

Keep in mind you can tinker around with the arguments and customize what you want to do on the destination Activity. You could also modify the value once you navigate to it. You can read more about it here in the docs.

like image 45
Mauker Avatar answered Sep 29 '22 12:09

Mauker