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/
Related
I am developing an android app using fragments. I have five fragments. Those are A,B,C,D,E . My first fragment A is the main fragment. First I traverse from A to B then from B to C. In C when I press back button I want it to go back to A. I have used the below code for calling B fragment from A. This same method is used for calling another fragments.
FragmentB fragment = new FragmentB();
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction().addToBackStack("tag");
transaction.replace(R.id.content_frame, fragment);
transaction.commit();
The back button code in the activity is as following
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
How to solve this issue please help me.
You can try this:
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} FragmentManager fragmentManager = getSupportFragmentManager();
int backCount = fragmentManager.getBackStackEntryCount();
System.out.println("back count " + backCount);
if(backCount==0)
{
actionBar.setTitle("Home");
//Here you can show alert dialog for exit the app?
}
/* else if(backCount==1)
{
}*/
else if(backCount==1)
{
fragmentManager.popBackStack();
// setTitle("Home");
navigationView.getMenu().getItem(0).setChecked(true);
actionBar.setTitle("Home");
}
else if(backCount>1)
{
for(int i=fragmentManager.getBackStackEntryCount();i>=1;i--)
{
fragmentManager.popBackStack();
System.out.println("back count loop" + fragmentManager.getBackStackEntryCount());
}
actionBar.setTitle("Home");
}
}
Try this:
#Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawers();
return;
}
// This code loads home fragment when back key is pressed
// when user is in other fragment than home
if (shouldLoadHomeFragOnBackPress) {
// checking if user is on other navigation menu
// rather than home
if (navItemIndex != 0) {
navItemIndex = 0;
CURRENT_TAG = TAG_HOME;
loadHomeFragment();
return;
}
}
super.onBackPressed();
}
Refer this reference : https://www.androidhive.info/2013/11/android-sliding-menu-using-navigation-drawer/
I am working with fragments in navigation drawer layout. I want to return to HomeFragment on pressing back button each time when any other fragment is visible in frame_container. and if home fragment is already visible i want to finish MainActivity (navigation_drawer_activity). Help me correct this code of OnBackPressed in main activity.
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_home);
if(fragment!=null && fragment.isVisible()){
clearBackStack();
finish();
}else {
clearBackStack();
getSupportFragmentManager().beginTransaction().replace(R.id.frame_container,new HomeFragment()).commit();
}
}
Here is the solution. I found the fragment from frame_container.
and then checked in if statement. if(fragment!=null && fragment instanceof HomeFragment && fragment.isVisible()). this returned home_fragment.
Thanks for your answers.
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.frame_container);
if(fragment!=null && fragment instanceof HomeFragment && fragment.isVisible()){
clearBackStack();
finish();
}else {
clearBackStack();
getSupportFragmentManager().beginTransaction().replace(R.id.frame_container,new HomeFragment()).commit();
}
}
try this
#Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START);
} else if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
getSupportFragmentManager().popBackStackImmediate();
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed();
}
}
I have two fragments namely FoodFragment and WishlistFragment these two are opened when i press their respective item clicks through the NavigationView
The problem I'm facing is when I press on the navigation items the fragments corresponding to them opens and everything works fine but when i press the back button, the MainActivity's onBackPressed() method is called and it only works for the first condition on the fragment that I've written.
Here's my code:
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
int id = item.getItemId();
mFragmentTransaction = getSupportFragmentManager().beginTransaction();
if (id == R.id.food) {
if(newFragment == null) {
newFragment = FoodFragment.newInstance("food", "fragment");
mFragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
mFragmentTransaction.replace(R.id.appBar, newFragment, "FoodFragment").addToBackStack("FoodFragment").commit();
}
}else if(id == R.id.wishlist){
if(wishFragment == null){
wishFragment = WishlistFragment.newInstance("wish", "fragment");
mFragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
mFragmentTransaction.replace(R.id.appBar, wishFragment, "WishFragment").addToBackStack("WishFragment").commit();
}
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
Here's the onBackPressed() method:
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
try {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if(getSupportFragmentManager().findFragmentByTag("WishFragment").isVisible()){
getSupportFragmentManager().popBackStack();
wishFragment = null;
}else if (getSupportFragmentManager().findFragmentByTag("FoodFragment").isVisible()) {
getSupportFragmentManager().popBackStack();
newFragment = null;
}else {
super.onBackPressed();
}
}catch (NullPointerException npe){
super.onBackPressed();
}
}
I've added tags to each fragment as you can see in the code and handling them through the onBackPressed() method. Here, when I open the WishFragment and press back button everything is cleared and so i can open the WishFragment again by pressing the Navigation Item corresponding to it. But, this seems to be getting wrong in case of FoodFragment when I open the fragment and press back button, the condition corresponding to it is not executed and So, I'm unable to open the FoodFragment again.
But, if I change the ordering of conditions in onBackPressed() like this:
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
try {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}else if (getSupportFragmentManager().findFragmentByTag("FoodFragment").isVisible()) {
getSupportFragmentManager().popBackStack();
newFragment = null;
} else if(getSupportFragmentManager().findFragmentByTag("WishFragment").isVisible()){
getSupportFragmentManager().popBackStack();
wishFragment = null;
}else {
super.onBackPressed();
}
}catch (NullPointerException npe){
super.onBackPressed();
}
}
It seems to work now with FoodFragment but not with WishFragment, as a result I was able to open the FoodFragment again but not the WishFragment. I've searched for this problem on many websites but, I cannot get the right answer.
I've resolved it by adding view.setOnKeyListener(//calling the MainActivity by KeyEvents) for the fragment but, this doesn't seem to be a good way to do things as it reloads my entire MainActivity again.
I don't know where I'm doing wrong. Please suggest me a better way to do this.
Thank you.
When the WishFragment is open and you press the back button
getSupportFragmentManager().findFragmentByTag("FoodFragment").isVisible()
This throws a NullPointerException.
So it will always do super.onBackPressed()since you are catching all the NullPointerException
To solve this change your if else statement to
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (getSupportFragmentManager().findFragmentByTag("FoodFragment") != null && getSupportFragmentManager().findFragmentByTag("FoodFragment").isVisible()) {
getSupportFragmentManager().popBackStack();
newFragment = null;
} else if(getSupportFragmentManager().findFragmentByTag("WishFragment") != null && getSupportFragmentManager().findFragmentByTag("WishFragment").isVisible()){
getSupportFragmentManager().popBackStack();
wishFragment = null;
} else {
super.onBackPressed();
}
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();
}
}
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();
}
}
}