Android Double Back Press to close the app having fragments - android

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?

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;
}
}

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();
}
}
}

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();
}

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

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;
}

#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();
}
}
}

Related

I want to close the app but do not go back to the previous Activity

I used an activity and several pieces in my app
sometimes when I'm on the first page (activity) and back pressed not going out of app and returns to the fragment or the same page
When this happens I've done a lot of work in the program
I used this code to fix this problem but
it also applied to the fragments
#Override
public void onBackPressed() {
this.finish();
}
Why returns to the fragment or the same page
How this problem is solved
I'm using this now
boolean doubleBackToExitPressedOnce = false;
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else if (!doubleBackToExitPressedOnce) {
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Click to exit again", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce = false;
}
}, 2000);
} else {
super.onBackPressed();
return;
}
}
Way is going to be a fragment
TabirFragment tabirFragment = new TabirFragment();
Bundle bundle = new Bundle();
bundle.putInt("id", id);
bundle.putString("name", name);
tabirFragment.setArguments(bundle);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction().addToBackStack(null);
transaction.replace(R.id.main_activity, tabirFragment).commit();
If you have multiple activities on the stack, then:
finish() - finishes the activity where it is called from and you see
the previous activity.
There is also system.exit but that would not work in your case:
System.exit(0) - restarts the app with one fewer activity on the
stack. So, if you called ActivityB from ActivityA, and System.exit(0)
is called in ActivityB, then the application will be killed and
started immediately with only one activity ActivityA
I recommend you use finishAffinity(). It will finish the current activity as well as all activities immediately below it. I remind you that it is supported by only API level 16+
several pieces what? fragments, getting trouble to understand, anyway if you want to manage frag and onBackPress, use this
private void setUpBackStackListener() {
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
Fragment currentFragment = getFragmentManager().findFragmentById(R.id.am_frameLayout);
if (currentFragment != null) {
int myCount = getFragmentManager().getBackStackEntryCount();
if (LOG_DEBUG) Log.e(TAG, "backStackCount : " + myCount);
String currentFragName = currentFragment.getClass().getSimpleName();
if (currentFragName.equalsIgnoreCase(FragOne.class.getSimpleName())) {
shouldExit = true;
} else if (currentFragName.equalsIgnoreCase(FragTwo.class.getSimpleName())) {
shouldExit = false;
}
}
}
}
});
}
#Override
public void onBackPressed() {
if (shouldExit == true) {
if (LOG_DEBUG)
Log.e(TAG, " Yeah exit douche:" + shouldExit + " isLastEntry : Testing :" + isLastEntry);
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
}
}
,if this not you seeking, you might want to clear what you want in a bit subtle way
When you used multiple fragment and activity When you switch activity by using method startActivity(), always use method finish(); when you back pressed then you will never get multiple activity and fragment and use onBackPressed method on main activity.
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;
}
}
The easiest solution i can give you is to keep no-history for the activity in the manifest file. and then override the back method for each activity.
<activity
android:name=".example"
android:noHistory="true">
</activity>

Fragment Back stack from second fragment to first fragment

I have viewpager tab fragment and from one tabb fragment on button click it open another fragment and another second fragment i want to add event of backpress as i am doing backpress it exiting application as i have written code of Double back press exit code in my root fragment and i dont want this code to call in my another second fragment as i want simply one step back to my previous fragment
As here is the code
R.id.Recharge -> {
val pl = Payment_History()
fragmentTransaction = fragmentManager!!.beginTransaction()
fragmentTransaction.replace(R.id.frame_container, paypal)
fragmentTransaction.addToBackStack(null)
fragmentTransaction.commit()
}
In Payment history i am calling on Back press override function
override fun onBackPressed(): Boolean {
super.onBackPressed()
}
and on clicking on Paymenthistory it called exit code from application. i want that it back to previous fragment. As I have written this fragment code but not working.
Any one have idea how to back second nested fragment to previous fragment.
My OnBackPress code in my MainActivity
override fun onBackPressed() {
// TODO Auto-generated method stub
try {
if (getFragmentManager().getBackStackEntryCount() == 0) {
if (doubleBackToExitPressedOnce) {
//super.onBackPressed();
val startMain = Intent(Intent.ACTION_MAIN)
startMain.addCategory(Intent.CATEGORY_HOME)
startMain.flags = Intent.FLAG_ACTIVITY_NEW_TASK
pref!!.setLoggedIn(true)
startMain.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
startMain.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(startMain)
return
}
this.doubleBackToExitPressedOnce = true
Toast.makeText(this, "Please click again to exit", Toast.LENGTH_SHORT).show()
Handler().postDelayed({ doubleBackToExitPressedOnce = false }, 2000)
}
}catch (e:Exception){
println("homemessage"+ e.message)
}
}
Add your fragment to backstack and then in your onBackPressed method do something like this:
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
this.finish();
}
}
For more information see this
Hope this is what you are looking for and it helps you.
Try this (Instead of "replace" use "add")
fragmentTransaction = fragmentManager!!.beginTransaction()
fragmentTransaction.add(R.id.frame_container, paypal)
fragmentTransaction.addToBackStack(null)
fragmentTransaction.commit()
and
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
this.finish();
}
}
if fragment within fragment back use this code onbackpreesed method
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if(getFragmentManager().getBackStackEntryCount() == 1) {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Check out")
.setMessage("want to do check out?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
closeApp();
}
})
.setNegativeButton("No",null)
.show();
}
else {
super.onBackPressed();
}
}
each fragment store in a stack
FragmentManager ff=getFragmentManager();
ff.beginTransaction().replace(R.id.main_content,new home()).addToBackStack(null).commit();
it's work in my project
I used this in Activity
Step 1:
Created a global variable for boolean
private boolean doubleBackToExitPressedOnce = false;
Step 2:
Then in onBackPress() method of activity
i did this
#Override
public void onBackPressed() {
if (mViewPager.getCurrentItem() > 0) {
//if any tab selected instead of tab 1
mDoubleBackToExitPressedOnce = false;
} else if (mViewPager.getCurrentItem() == 0) {
//if tab 1 selected
mDoubleBackToExitPressedOnce = true;
if (mDoubleBackToExitPressedOnce)
super.onBackPressed();
}
mViewPager.setCurrentItem(0);//go to tab 1
}
I was also Struggling in this regard. after a lot of research i found a solution that we have to call super.onBackPressed() where our last or home fragment is Active
Solution
override fun onBackPressed() {
val activeFragment = this.supportFragmentManager.
findFragmentById(R.id.frame_layout)
if (activeFragment is HomeFragment){
startActivity(Intent(this, DashBoardActivity::class.java))
finish()
super.onBackPressed()
}
else
{
val ft: FragmentTransaction
=supportFragmentManager.beginTransaction()
//should not call super.onBackPressed()
switchFragment(ft)
}
//nor here you should call super.onBackPressed()
}
and the switchFragment function is
fun switchFragment(ft:FragmentTransaction) {
try {
ft.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right)
if (supportFragmentManager.findFragmentById(R.id.frame_layout) == null) {
ft.add(R.id.frame_layout, HomeFragment())
} else {
ft.replace(R.id.frame_layout, HomeFragment())
println("Comess")
}
ft.addToBackStack(null)
ft.commit()
} catch (e: Exception) {
e.printStackTrace()
}
}

Navigation Drawer Backstacks with Fragments

My app uses a navigation drawer with 2 sections.
Section 1: Character List, Favorites List
Section 2: List of all characters
Character List has the same character selections as section 2 in the navigation drawer. Selecting a character from "Character List" or "Favorites List" in section 1, or from the list in the drawer, will open the character page.
When I am on a character page, I want the back button to bring the user back to the Character List or Favorites List (whichever was last accessed), but never back to a previous Character Page (if it was selected from the navigation drawer).
My Drawer item listener:
public void getDrawerItemClickListener() {
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
public boolean onNavigationItemSelected(MenuItem menuItem) {
mDrawerLayout.closeDrawers();
int selection = menuItem.getItemId();
String name = menuItem.getTitle().toString();
if(selection == R.id.nav_home) {
Fragment myFragment = new HomeFragment();
replaceFragment(myFragment);
}
if(selection == R.id.nav_fav) {
Fragment myFragment = new FavFragment();
replaceFragment(myFragment);
}
for(int i = 0; i < characters.size(); i++) {
if(characters.get(i).getName().equals(name))
{
Fragment myFragment = new TabFragment();
myFragment.setArguments(createCharacterBundle(characters.get(i)));
replaceFragment(myFragment);
break;
}
}
return false;
}
});
}
My replaceFragment method:
public void replaceFragment(Fragment myFragment) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.replace(R.id.containerView, myFragment);
transaction.commit();
}
And my onBackPressed method:
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
mDrawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
}
#Override
public void onDrawerOpened(View drawerView) {
mDrawerOpen = true;
}
#Override
public void onDrawerClosed(View drawerView) {
mDrawerOpen = false;
}
#Override
public void onDrawerStateChanged(int newState) {
}
});
public void onBackPressed() {
if (mDrawerOpen) {
mDrawerLayout.closeDrawer(DrawableItemResourceID);
return;
} else {
super.onBackPressed();
}
}

Onbackpressed redirect to particular fragment

In my app i have navigation drawer,So i have one MainActivity and rest are fragments. My app is working fine. Whenever i press back button it redirect to previous fragment.it works fine.but what i want is after successful payment i am displaying Successful payment page,on this page when user press back button i want to redirect to HomeFragment,but right now it goes to Placeorder fragment.
#Override
public void onBackPressed() {
if(getFragmentManager().getBackStackEntryCount() == 0) {
super.onBackPressed();
}
else {
getFragmentManager().popBackStack();
}
}
Override your onBackPress method:
#Override
public void onBackPressed() {
if (fragment != null && fragment.getChildFragmentManager().getBackStackEntryCount() > 0){
fragment.getChildFragmentManager().popBackStack();
}else {
super.onBackPressed();
}
}
One way would be saving previous fragment (previousFragment) variable while opening new fragment and making it null when you are in first or placeholder fragment .... then check value of previousFragment inside onBackPressed method , if null perform exit operation else replace fragment with previousFragment by which you will get back to previous fragment on back press.
You should simulate function as below in abstract class fragment
/**
* Handle "Back" key pressed.
* #return TRUE if the "Back" key pressed was handled. FALSE indicate it's not handled and parent class can handle it.
*/
public abstract boolean onBackPressed()
And in MainActivity, you will handle this function
#Override
public void onBackPressed() {
if (mSelectedFragment != null && mSelectedFragment.onBackPressed()) {
return;
} else {
super.onBackPressed
}
}
inside your onBackPressed() do like this:
#Override
public void onBackPressed() {
if(getSupportFragmentManger.findFragmentByTag("paymentFragment") != null){
//add homeFragment;
}
else{
if(getFragmentManager().getBackStackEntryCount() == 0) {
super.onBackPressed();
}
else {
getFragmentManager().popBackStack();
}
}
}
you can set some global variable (true when payment is success else false) in Application class and in onbackpressed of your activity just check that variable is true or not.Then in backpressed of your activity call this function.
public void clearBackStack() {
FragmentManager manager = getSupportFragmentManager();
if (manager.getBackStackEntryCount() > 0) {
FragmentManager.BackStackEntry first = manager.getBackStackEntryAt(0);
manager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Use:
fragmentTransaction.replace(R.id.fragment_container, mFeedFragment);
fragmentTransaction.commit();
Don't do this:
fragmentTransaction.addToBackStack(null);
Follow this simple method
declare an integer as
public int count;
initialise this count as count=0 in your main page
now include this in your main activity
#Override
public void onBackPressed() {
if (count == 1) {
if (exit) {
super.onBackPressed();
return;
} 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;
}
}, 2000);
}
}else {
toolbar.setTitle("Home");
mDrawerLayout.closeDrawers();
count=1;
display(0);
}
}

OnBackPressed() quits application

My onBackPressed() sends me out of my app. How can I avoid this? Either it should send me back to last shown fragment or just send me to a specific fragment.
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else{
super.onBackPressed();
}
}
Try this,If you are using Fragment android.support.v4.app.Fragment.
private boolean allowExit = false;
Then
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
// handling fragment backbutton navigation
getSupportFragmentManager().popBackStack();
} else {
if (allowExit) {
super.onBackPressed();
} else {
Toast.makeText(this, getString(R.string.app_exit_message), Toast.LENGTH_SHORT).show();
allowExit = true;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
allowExit = false;
}
}, 3000);
}
}
}
If you are using not support fragment you have to replace
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else if (getFragmentManager().getBackStackEntryCount() > 0) {
// handling fragment backbutton navigation
getFragmentManager().popBackStack();
} else {
if (allowExit) {
super.onBackPressed();
} else {
Toast.makeText(this, getString(R.string.app_exit_message), Toast.LENGTH_SHORT).show();
allowExit = true;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
allowExit = false;
}
}, 3000);
}
}
}
And add message to the string.xml
<string name="app_exit_message">Press again to exit</string>
Try the below code.
1. If your drawer is opened it will close the drawer.
2. If Any fragment is in backstack, it will navigate you to the previous fragment.
3. If No Fragment is in backstack, it will close the application.
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
oneStepBack();
}
}
/**
* function to go back to previous fragment
*/
private void oneStepBack() {
FragmentTransaction fts = getSupportFragmentManager().beginTransaction();
FragmentManager fragmentManager = getSupportFragmentManager();
showOutput("Back Stack Count>>>>>>>>>>" + fragmentManager.getBackStackEntryCount());
if (fragmentManager.getBackStackEntryCount() >= 2) {
fragmentManager.popBackStackImmediate();
fts.commit();
} else {
finish();
}
}
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else{
write your code here what activity you want to open on back press and remove below line
//super.onBackPressed();
}
}
DrawerLayout should be initialised in onCreate() method ,so you are facing the problem.
For your reference check this , it may help you.
http://www.androidhive.info/2013/11/android-sliding-menu-using-navigation-drawer/

Categories

Resources