Android Double Back Press to close the app having fragments
Asked Answered
M

6

6

I followed this tutorial and certain similar answers on SO.

My present onBackPressed code is as follows -

private static final int TIME_DELAY = 2000;
private static long back_pressed;

@Override
public void onBackPressed() {
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    if (drawer.isDrawerOpen(GravityCompat.START)) {
        drawer.closeDrawer(GravityCompat.START);
    } else {
        int fragments = getFragmentManager().getBackStackEntryCount();
        if (fragments > 0) {
            super.onBackPressed();
        } else {
            if (back_pressed + TIME_DELAY > System.currentTimeMillis()) {
                super.onBackPressed();
            } else {
                Toast.makeText(getBaseContext(), "Press once again to exit!",
                        Toast.LENGTH_SHORT).show();
            }
            back_pressed = System.currentTimeMillis();
        }
    }
}

I am adding fragments to back stack like this (and at some places I don't add to back stack) -

private void LoadSignDetailsFragment() {
    Bundle args = new Bundle();
    Fragment fragment = new SignDetailsFragment();
    args.putBoolean("hasValues", true);
    args.putBoolean("showBookmarkedSignsOnly", showBookmarkedSignsOnly);
    args.putInt("sign_id", signId);
    if (fragment != null) {
        FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
        fragment.setArguments(args);
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit);
        fragmentTransaction.replace(R.id.container_body, fragment);
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
    }
}

What I am trying to do is, if there is any fragment in backstack, single onBackPressed migrate to previous fragment. But, if there no Fragment in backstack, it should display Toast for double back press to close the app.

My present code, always shows the Toast, and asks for Double back press irrespective of presence/absence of fragments in backstack. I am unable to figure out why?

Marilumarilyn answered 25/11, 2015 at 7:8 Comment(1)
See the documentation of getStackEntryAt(int i) and getStackEntryCount() here developer.android.com/reference/android/app/… and modify the below answers by adding some if conditions in onBackPressed()Gonophore
S
29

You can refer to below code for your need. If you are not using v4 support fragment, then you have to use getFragmentManager() instead of getSupportFragmentManager() to get the backstack count. Here I am using boolean value to check if back is clicked, if in 2 seconds it is not clicked again, it will become false again.

boolean doubleBackToExitPressedOnce = false;
@Override
public void onBackPressed() {
    //Checking for fragment count on backstack
    if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
        getSupportFragmentManager().popBackStack();
    } else if (!doubleBackToExitPressedOnce) {
        this.doubleBackToExitPressedOnce = true;
        Toast.makeText(this,"Please click BACK again to exit.", Toast.LENGTH_SHORT).show();

        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                doubleBackToExitPressedOnce = false;
            }
        }, 2000);
    } else {
        super.onBackPressed();
        return;
    }
}
Shading answered 25/11, 2015 at 7:44 Comment(2)
Thanks, from your explanation only, I found out that, I am using v4 support fragment, but by mistake i was using getFragmentManager() instead of getSupportFragmentManager(). After this correction, even my code sample worked. :)Marilumarilyn
Awesome! Have a nice day.Shading
P
1
private boolean doubleBackToExitPressedOnce = true;
    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            if (doubleBackToExitPressedOnce) {
                this.doubleBackToExitPressedOnce = false;
                Toast.makeText(this,"Please click BACK again to exit.", Toast.LENGTH_SHORT).show();
            } else {
                finish();
            }
        }
    }
Parole answered 5/9, 2017 at 7:31 Comment(0)
R
1
   @Override
   public void onBackPressed() {
       DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
       if (drawer.isDrawerOpen(GravityCompat.START)) {
          drawer.closeDrawer(GravityCompat.START);
       } else {
     //if navigation drawer here navhostfragment is primary fragment
       int fragments = 
                 getSupportFragmentManager().getPrimaryNavigationFragment()
                .getChildFragmentManager().getBackStackEntryCount();
       if (fragments > 0) {
          super.onBackPressed();
       } else {
           if (back_pressed + TIME_DELAY > System.currentTimeMillis()) {
               super.onBackPressed();
           } else {
                   Toast.makeText(getBaseContext(), "Press once again to exit!",
                    Toast.LENGTH_SHORT).show();
            }
           back_pressed = System.currentTimeMillis();
        }
      }
    }
Rubio answered 21/2, 2022 at 12:53 Comment(0)
S
0

do this in simple way use below code

Boolean doubleBackToExitPressedOnce = false;

@Override
public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        super.onBackPressed();

        System.exit(0);

        return;
    }
    this.doubleBackToExitPressedOnce = true;
    Toast.makeText(this, "Please click BACK again to exit",
            Toast.LENGTH_SHORT).show();

}
Spracklen answered 25/11, 2015 at 7:12 Comment(2)
how this gonna work ? once user pressed back button the flag will be marked as true, so after some time if he press again the app will exit without promptKeane
on first click flag is true on second click it goes in if condition to closeSpracklen
K
0

add this code in your fragment onCreateView

    view.setOnKeyListener( new OnKeyListener()
{
  private Boolean exit = false;
    @Override
    public boolean onKey( View v, int keyCode, KeyEvent event )
    {
        if( keyCode == KeyEvent.KEYCODE_BACK )
        {
        //logic for identifying double back press, expires after 3 seconds
         if (exit) {
            getActivity().finish(); // finish activity
        } else {
            Toast.makeText(this, "Press Back again to Exit.",
                    Toast.LENGTH_SHORT).show();
            exit = true;
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    exit = false;
                }
            }, 3 * 1000);

        }
            return true;
        }
        return false;
    }
} );

or if you want yo add it in your activity you have to override onBackPressed methhod and add the same code.

example

private Boolean exit = false;

@Override
public void onBackPressed(){

if (exit) {
            finish(); // finish activity
        } else {
            Toast.makeText(this, "Press Back again to Exit.",
                    Toast.LENGTH_SHORT).show();
            exit = true;
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    exit = false;
                }
            }, 3 * 1000);

        }    
}

but it is is recommended to do it in activity other than fragment

Keane answered 25/11, 2015 at 7:14 Comment(1)
Sorry, your previous solution didn't work for me. I tried with adding the first code sample to one of fragment, which on back pressed, just moved back to another fragment, no Toast displayed. And even for your updated answer, How does both of your code samples identifies, that if there is any fragment in backstack, move to it or else show message for double back press?Marilumarilyn
B
0

The way w/o handler:

@Override
public void onBackPressed() { 
    long currentMillis = System.currentTimeMillis();
    if (currentMillis - this.lastPressed < 2000 && getFragmentManager().getBackStackEntryCount() > 0) {
         getFragmentManager().popBackStack();
    } else {
        // show toast if you need
    }
    this.lastPressed = currentMillis;
}
Bernard answered 16/5, 2018 at 8:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.