问题
I'm in a pickle and can't understand what's going on. I have my app using an OnBackPressed with a closing window and a home screen check, in short "if home, else, use exit menu"
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (!viewIsAtHome) {
displayView(R.id.nav_large_monsters);
} else {
new AlertDialog.Builder(this)
.setMessage("Are you sure you want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Home.this.finish();
}
})
.setNegativeButton("No", null)
.show();
}
}
What's happening that I don't want happening is that pressing back takes me straight back to my "Large Monsters" fragment. I'm wanting this to follow the backstack.
I have about 30 buttons on the Large Monsters page that takes you into a Monster's information, but pressing back immediately brings up the "Are you sure you want to quit" menu, instead of going back to the Large Monster Fragment:
Large Monsters
Pressing Back button from a Monster fragment
Clearly it's not following the backstack. Same with any other screen, if I go any other fragment, it'll take me straight back to Nav_Large_Monsters instead of following the backstack.
I'm assuming my issue is this:
} else if (!viewIsAtHome) {
displayView(R.id.nav_large_monsters);
But if I remove it, the app will want to immediately ask for exit, not return home, still not following the backstack.
If I return the onBackPressed back to its default code, it'll follow backstack, but it won't load a home fragment and start with a blank fragment.
Attempted:
I've attempted to remove the " else if (!viewIsAtHome)" section in onBackPressed, and implemented "default" in my onNavigationItemSelected method
default: fragment = new Large_Monsters(); break;
This too did not work. Does not load a home fragment.
Previously I had a showHome() method, and this DID work for being able to use the backStack and use a home fragment, but after changing my Fragments to v4.support.app.Fragment, I had to change up how my Home Activity handled my onNavigationItemSelected. It did not like my showHome method and kept calling out that I was using the old FragmentManager and not v4.support.app.FragmentManager(this method caused my app to crash immediately after changing to v4):
private void showHome() { fragment = new Large_Monsters(); if (fragment != null) { android.app.FragmentManager fragMgmt = getFragmentManager(); fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit(); }
}
I also attempted adding an If statement about popping backStack, and this did not seem to do anything productive:
if (!fragment.getFragmentManager().popBackStackImmediate()) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { finishAfterTransition(); } }
I also attempted adding an If statement checking if Backstack was > 0 but that also did not help, although I deleted that string and unsure where I found it. Maybe I built that string incorrectly.
Any assistance would be great! Thanks!
Code:
Home.java (MainActivity, I just named it Home on this project)
public class Home extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private Fragment fragment = null;
private FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DatabaseHelper myDbHelper = new DatabaseHelper(Home.this);
try {
myDbHelper.createDataBase();
} catch (IOException ioe) {
throw new Error("Unable to create database");
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
navigationView.setItemIconTintList(null);
// showHome();
displayView(R.id.nav_large_monsters);
}
private boolean viewIsAtHome;
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (!viewIsAtHome) {
displayView(R.id.nav_large_monsters);
} else {
new AlertDialog.Builder(this)
.setMessage("Are you sure you want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Home.this.finish();
}
})
.setNegativeButton("No", null)
.show();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
return super.onOptionsItemSelected(item);
}
// private void showHome() {
// fragment = new Large_Monsters();
// if (fragment != null) {
// android.app.FragmentManager fragMgmt = getFragmentManager();
// fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
// }
// }
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
displayView(item.getItemId());
return true;
}
public void displayView(int viewId) {
Fragment fragment = null;
String title = getString(R.string.app_name);
switch (viewId) {
case R.id.nav_large_monsters:
fragment = new Large_Monsters();
title = "Large Monsters";
viewIsAtHome = true;
break;
case R.id.nav_small_monsters:
fragment = new Small_Monsters();
title = "Small Monsters";
viewIsAtHome = false;
break;
case R.id.nav_weapons:
fragment = new Weapons();
title = "Weapons";
viewIsAtHome = false;
break;
case R.id.nav_armors:
fragment = new Armors_Low_High();
title = "Armor Sets";
viewIsAtHome = false;
break;
case R.id.nav_charms:
fragment = new Charms();
title = "Charms";
viewIsAtHome = false;
break;
case R.id.nav_items:
fragment = new Items();
title = "Items";
viewIsAtHome = false;
break;
case R.id.palico_armor:
fragment = new Palico_Armor();
title = "Palico Armor";
viewIsAtHome = false;
break;
case R.id.palico_gadgets:
fragment = new Palico_Gadgets();
title = "Palico Gadgets";
viewIsAtHome = false;
break;
case R.id.palico_weps:
fragment = new Palico_Weapons();
title = "Palico Weapons";
viewIsAtHome = false;
break;
case R.id.palico_helms:
fragment = new Palico_Helms();
title = "Palico Helmets";
viewIsAtHome = false;
break;
default:
fragment = new Large_Monsters();
break;
}
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment, fragment.getTag())
.addToBackStack(null);
ft.commit();
}
// set the toolbar title
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(title);
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
}
回答1:
If you're going to override onBackPressed
, you have to handle the undoing of the backstrack yourself. This is what a FragmentActivity
does:
/**
* Take care of popping the fragment back stack or finishing the activity
* as appropriate.
*/
@Override
public void onBackPressed() {
FragmentManager fragmentManager = mFragments.getSupportFragmentManager();
final boolean isStateSaved = fragmentManager.isStateSaved();
if (isStateSaved && Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
// Older versions will throw an exception from the framework
// FragmentManager.popBackStackImmediate(), so we'll just
// return here. The Activity is likely already on its way out
// since the fragmentManager has already been saved.
return;
}
if (isStateSaved || !fragmentManager.popBackStackImmediate()) {
super.onBackPressed();
}
}
If you skip that, you don't get the fragment popping behavior. So just update your onBackPressed
to include a pop of the fragment manager - if it succeeds, you can return early because the system did its thing popping the fragment as desired.
@Override
public void onBackPressed() {
// Pressing back popped the back stack, nothing else to do
FragmentManager fragmentManager = getSupportFragmentManager();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (!fragmentManager.isStateSaved() && fragmentManager.popBackStackImmediate()) {
return;
} else {
new AlertDialog.Builder(this)
.setMessage("Are you sure you want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Home.this.finish();
}
})
.setNegativeButton("No", null)
.show();
}
}
UPDATE
You also need to update your displayView
method, because right now it's always pushing something on the stack. So your "home" fragment will actually be the first thing on the stack and will pop leaving you with a blank screen. So if you're showing the "home" fragment, do not call addToBackStack
on the fragment manager.
Further, you should not need to explicitly set the "home" fragment on pressing back as popping the backstack should do the right thing (see updated example above).
Hope that helps!
来源:https://stackoverflow.com/questions/49968397/onbackpressed-not-following-backstack-goes-directly-to-home-fragment