Handle onBackPressed in Android Navigation Component
Asked Answered
U

3

6

I have implemented navigation Drawer with Navigation Components in Android. I have 5 fragments that I want to go back to my HomeFragment when I click on back pressed. For the moment they stay onBackStack and do not go to my desired fragment but go to whatever fragment was first. This is my nav_graph :

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            app:startDestination="@id/setupFragment"
            android:id="@+id/treasure_nav"
            android:label="Pick a country">
    <fragment android:id="@+id/homeFragment"
              android:name="com.stavro_xhardha.pockettreasure.ui.home.HomeFragment"
              android:label="Home"
              tools:layout="@layout/fragment_home">
        <action android:id="@+id/action_home_fragment_to_namesFragment2"
                app:popUpTo="@id/homeFragment"
                app:destination="@id/namesFragment"/>
        <action android:id="@+id/action_home_fragment_to_quranFragment"
                app:popUpTo="@id/homeFragment"
                app:destination="@id/quranFragment"/>
        <action android:id="@+id/action_homeFragment_to_tasbeehFragment"
                app:popUpTo="@id/homeFragment"
                app:destination="@id/tasbeehFragment"/>
        <action android:id="@+id/action_homeFragment_to_galleryFragment"
                app:popUpTo="@id/homeFragment"
                app:destination="@id/galleryFragment"/>
        <action android:id="@+id/action_homeFragment_to_newsFragment"
                app:popUpTo="@id/homeFragment"
                app:destination="@id/newsFragment"/>
        <action android:id="@+id/action_homeFragment_to_settingsFragment"
                app:popUpTo="@id/homeFragment"
                app:destination="@id/settingsFragment"/>
    </fragment>
    <fragment
            android:id="@+id/namesFragment"
            android:name="com.stavro_xhardha.pockettreasure.ui.names.NamesFragment"
            android:label="Names of Allah"
            tools:layout="@layout/fragment_names"/>
    <fragment
            android:id="@+id/quranFragment"
            android:name="com.stavro_xhardha.pockettreasure.ui.quran.QuranFragment"
            android:label="Quran"
            tools:layout="@layout/fragment_quran"/>
    <fragment android:id="@+id/tasbeehFragment"
              android:name="com.stavro_xhardha.pockettreasure.ui.tasbeeh.TasbeehFragment"
              android:label="Tasbeeh"
              tools:layout="@layout/fragment_tasbeeh"/>
    <fragment android:id="@+id/galleryFragment"
              android:name="com.stavro_xhardha.pockettreasure.ui.gallery.GalleryFragment"
              android:label="Gallery"
              tools:layout="@layout/fragment_gallery"/>
    <fragment android:id="@+id/newsFragment"
              android:name="com.stavro_xhardha.pockettreasure.ui.news.NewsFragment"
              android:label="News"
              tools:layout="@layout/fragment_news"/>
    <fragment android:id="@+id/settingsFragment"
              android:name="com.stavro_xhardha.pockettreasure.ui.settings.SettingsFragment"
              android:label="Settings"
              tools:layout="@layout/fragment_settings"/>
    <fragment android:id="@+id/setupFragment"
              android:name="com.stavro_xhardha.pockettreasure.ui.setup.SetupFragment"
              android:label="Pick country"
              tools:layout="@layout/fragment_setup">
        <action android:id="@+id/action_setupFragment_to_homeFragment3"
                app:destination="@+id/homeFragment"
                app:launchSingleTop="true"
                app:popUpTo="@+id/treasure_nav"
                app:popUpToInclusive="true"/>
    </fragment>
</navigation>

And this is my onBackPressed in my MainActivity (and the only one) :

override fun onBackPressed() {
        if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
            drawer_layout.closeDrawer(GravityCompat.START)
        } else {
                super.onBackPressed()
        }
    }

Edit: When i remove the super.onBackPressed() and replace it with : findNavController(R.id.nav_host_fragment).popBackStack(R.id.homeFragment, false) I achieve what I want. The only problem is that when I am in the homeFragment I want to end the app but I can't.

Univocal answered 20/5, 2019 at 8:50 Comment(3)
couldnt understand the problem from your statment. can you elaborate what actually you want to do on backPress? I have concluded two situations from your statement. One if you have selected any item from nav, then on backpress you want to go to home screen. and again on backpress want to exit the app. Second that on back press you want to change the fragment to home and exit immediate.Pyroxylin
first of all when you are replacing fragments over eachother, you have to use replace fragment instead of add fragment so that they wont stay in backStackPyroxylin
where do you see the replace or the add method o.OUnivocal
H
8

If my understanding is correct, you want to go back to HomeFragment wherever you are in the navigation flow. For this case you could try registering OnBackPressedCallback on your Fragments via addOnBackPressedCallback, and call popBackStack to navigate to your HomeFragment. Try adding this to Fragments' onViewCreated that need to go back to HomeFragment on backpress:

@Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        navController = Navigation.findNavController(view);

        requireActivity().addOnBackPressedCallback(getViewLifecycleOwner(), () -> {
               navController.popBackStack(R.id.homeFragment, false);
            });
            return true;
        });
Hinch answered 30/5, 2019 at 2:21 Comment(1)
You did solve my issue although looks like I'm having a lower API, and I am going to update the answer a littleUnivocal
A
6

If you want to close app when press back in HomeFragment, it's just specified these attributes of the last action that navigates you to this destination:

  1. app:popUpToInclusive to true
  2. app:popUpTo to of the last fragment(SetupFragment) that navigates you here(HomeFragment)

It means change your code like this:

<fragment android:id="@+id/setupFragment"
          android:name="com.stavro_xhardha.pockettreasure.ui.setup.SetupFragment"
          android:label="Pick country"
          tools:layout="@layout/fragment_setup">
    <action android:id="@+id/action_setupFragment_to_homeFragment3"
            app:destination="@+id/homeFragment"
            app:launchSingleTop="true"
            app:popUpTo="@+id/setupFragment"          // this line changes
            app:popUpToInclusive="true" />            // and this requires too
</fragment>
Annelieseannelise answered 23/5, 2019 at 22:26 Comment(4)
No, I am already ok with that. What I need is that when I go from HomeFragment to fragment Gallery, and than to fragment Settings, and than press back, it sends me to the Settings fragment. I dont want this , I want to get back to HomeFragmentUnivocal
You are in settings and after press back it sends you to settings? wow!Annelieseannelise
hello, im really sory about that. it was a mistake: To make the case clear: When Navigate from Home -> GalleryFragment -> SettingsFragment. On SettingsFragment when I press back, it sends me to the GalleryFragment. I want to go to HomeFragment.Univocal
this doesn't work also :(Heliochrome
M
0

I made this extension function to do just that:

fun Fragment.setupOnBackPressedCallback(block: () -> Unit) {
    requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner,
        object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() = block.invoke()
        }
    )
}

Inside your fragment, all you have to do is call it passing a lambda:

setupOnBackPressedCallback {
    // Do what you want when you press the back button
}
Mallemuck answered 13/3, 2023 at 21:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.