Search code examples
javaandroidandroid-fragmentsactivity-lifecycleonbackpressed

Problem with getOnBackPressedDispatcher while Handling Fragment Backstack


In my single-activity app, I've implemented a feature where pressing the back button in the main activity triggers a delayed exit sequence, displaying a 'Goodebye' message before closing the app. This functionality works as expected. However, I've encountered an issue: when navigating from a fragment back to the main activity when pressing the back button, instead of returning to the main activity, the app exits.

Here's how I've set up the back press in the main activity:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
        @Override
        public void handleOnBackPressed() {
            exitAppWithDelay();
        }
    });
}

private void exitAppWithDelay() {
        recyclerView.setVisibility(View.GONE);
        appBarLayout.setVisibility(View.GONE);
        goodbyText.setVisibility(View.VISIBLE);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {

                finish(); // Finish the MainActivity after starting the GoodbyeScreen
            }
        }, EXIT_DELAY);
    }

Additionally, when navigating to fragments from the main activity,Here is code:

private void openFragmentBasedOnPosition(int position) {
    FragmentTransaction transaction = fragmentManager.beginTransaction();

    Fragment fragment = null;
    String fragmentTag = null;

    switch (position) {
          case 0:
                fragment = new make_everything_ok_btn();
                fragmentTag = "make_everything_ok_btn";
                break; // And then other cases 

    }

    if (fragment != null) {
        transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out,android.R.anim.fade_in, android.R.anim.fade_out);
        transaction.replace(R.id.fragment_container, fragment, fragmentTag);
        transaction.addToBackStack(null);
        transaction.commit();
    }
}

And in a specific fragment, I have a button click listener that restarts the fragment:

continueBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        requireActivity().getSupportFragmentManager().popBackStack();
        FragmentTransaction transaction = requireActivity().getSupportFragmentManager().beginTransaction();
        transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out,android.R.anim.fade_in, android.R.anim.fade_out);                
        transaction.replace(R.id.fragment_container, new make_everything_ok_btn());
        transaction.addToBackStack(null);
        transaction.commit();
    }
});

The issue seems to arise from the back button handling mechanism conflicting with the fragment navigation. I'm unsure why this issue occurs, especially since it wasn't present before implementing the back button handling in the main activity.


Solution

  • Modified Answer again (try this)

    In main activity, you can maintain a flag to indicate whether the back button press should trigger the exit sequence or navigate back in the fragment stack:

    getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
                @Override
                public void handleOnBackPressed() {
                    if (isFragmentBackStackEmpty()) {
                        exitAppWithDelay();
                    } else {
                        // If there are fragments in the back stack, proceed with default back navigation
                        getSupportFragmentManager().popBackStack();
                    }
                }
            });
    
    
    private boolean isFragmentBackStackEmpty() {
            return getSupportFragmentManager().getBackStackEntryCount() == 0;
        }