Search code examples
androidnavigationfragmentandroid-jetpack

Handling back button in Android Navigation Component


I'd like to know how properly handle system back button action using Navigation Controller. In my app I have two fragments (for ex. fragment1 and fragment2) and I have an action in fragment1 with destination to fragment2. Everything works well except one thing - when user presses system back button in fragment2 I want to show a dialog (using DialogFragment for example) to confirm exit. What is the best way to implement this behavior? If I use app:defaultNavHost="true" in my host fragment then it automatically goes back ignoring my rules. And, additionally, what is this component for?

enter image description here

Should I use "pop to" may be?


Solution

  • Newest Update - April 25th, 2019

    New release androidx.activity ver. 1.0.0-alpha07 brings some changes

    More explanations in android official guide: Provide custom back navigation

    Example:

    public class MyFragment extends Fragment {
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // This callback will only be called when MyFragment is at least Started.
            OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
                @Override
                public void handleOnBackPressed() {
                    // Handle the back button event
                }
            };
            requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
    
            // The callback can be enabled or disabled here or in handleOnBackPressed()
        }
        ...
    }
    

    Old Updates

    UPD: April 3rd, 2019

    Now its simplified. More info here

    Example:

    requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), this);
    
    @Override
    public boolean handleOnBackPressed() {
        //Do your job here
        //use next line if you just need navigate up
        //NavHostFragment.findNavController(this).navigateUp(); 
        //Log.e(getClass().getSimpleName(), "handleOnBackPressed");
        return true;
        }
    

    Deprecated (since Version 1.0.0-alpha06 April 3rd, 2019) :

    Since this, it can be implemented just using JetPack implementation OnBackPressedCallback in your fragment and add it to activity: getActivity().addOnBackPressedCallback(getViewLifecycleOwner(),this);

    Your fragment should looks like this:

    public MyFragment extends Fragment implements OnBackPressedCallback {
    
        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            
            getActivity().addOnBackPressedCallback(getViewLifecycleOwner(),this);
    }
        
        @Override
        public boolean handleOnBackPressed() {
            //Do your job here
            //use next line if you just need navigate up
            //NavHostFragment.findNavController(this).navigateUp(); 
            //Log.e(getClass().getSimpleName(), "handleOnBackPressed");
            return true;
        }
    
        @Override
        public void onDestroyView() {
            super.onDestroyView();
            getActivity().removeOnBackPressedCallback(this);
        }
    }
    

    UPD: Your activity should extends AppCompatActivityor FragmentActivity and in Gradle file:

     implementation 'androidx.appcompat:appcompat:{lastVersion}'