In my application, I have 5 fragments and the requirement is that on any given fragment, if back button is pressed, it should exit out of the application. In other words the fragments does not have any order and are independent. SO pressing the back button on any fragment will actually close the app itself.
In some fragments, I am opening other fragments using this code:
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
track nextFrag= new track();
login.this.getFragmentManager().beginTransaction()
.replace(R.id.content_frame, nextFrag, null)
.addToBackStack(null)
.commit();
However the history is still maintained, What can I do to clear the history on start of any fragment.
EDIT:
Tried this and the application does exit on pressing back, however I can still see a glimpse of previous activity and it throws some nasty exceptions.
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
finish();
}
}
Related
I handle my back navigation like such:
When creating / committing a Fragment:
getSupportFragmentManager()
.beginTransaction()
.addToBackStack("ToDoFragment")
.replace(R.id.content_frame, fragmentR, fragmentR.getClass().getSimpleName())
.commit();
When catching a back button press:
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
// If navigation drawer is open, close it
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
setDrawerState(true);
displayMenu(true);
}
}
This works fine for my Fragments, but I wish to do the same for my PreferenceFragment, that I call like such:
getFragmentManager().beginTransaction()
.add("ToDoFragment")
.replace(R.id.content_frame, new SettingsFragment()).commit();
But when pressing my back nav. button it does not bring me back to the previous Fragment, instead it overlaps my Settings view and my previous Fragment.
What am I missing / not understanding?
EDIT:
I have added getFragmentManager().popBackStackImmediate(); to my onBackPressed() method, I do not have any view overlapping, but when going into my settings and pressing back, the Fragment is empty.
Using a PreferenceFragment you canĀ“t override onBackPressed() in this case use onDetach() :
#Override
public void onDetach() {
super.onDetach();
//Do your process here!
}
Instead of using 'add' in manager use 'addtoBackStack' Because add retains the existing fragments and adds a new fragment which means existing fragment will be active. Hence back button is not called for existing fragment.
getFragmentManager().beginTransaction()
.addToBackStack("ToDoFragment")
.replace(R.id.content_frame, new SettingsFragment()).commit();
I have Base Activity including NavigationView with 2 menu items. On start it loads Home fragment having background image inside it. Each loads specific fragment. When I select Terms & Conditions menu item, it loads T&C fragment & when I press back button it simply kills it.
However, when I select About Us menu item, it loads About Us fragment but I need to press BACK button twice to kill it. I need to know why does it happen?
Part of Code in AppBaseActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
HomeFragment homeFragment = new HomeFragment();
fragmentTransaction.add(R.id.body_container, homeFragment, "");
fragmentTransaction.commit();
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
navigationView.getMenu().findItem(item.getItemId()).setChecked(true);
switch (item.getItemId()) {
case R.id.nav_terms :
fragmentTransaction = fragmentManager.beginTransaction();
TCFragment tcFragment = new TCFragment();
fragmentTransaction.replace(R.id.body_container, tcFragment, "");
fragmentTransaction.commit();
break;
case R.id.nav_about_us :
fragmentTransaction = fragmentManager.beginTransaction();
AboutUsFragment aboutUsFragment = new AboutUsFragment();
fragmentTransaction.replace(R.id.body_container, aboutUsFragment, "");
fragmentTransaction.commit();
break;
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
All fragments simply have overridden onCreateView() by inflating respected xml only. No code is written in both fragments yet.
You can stop back hardware navigation if you want.
Simply using onBackPressed() without super.onBackPressed()
#Override
public void onBackPressed() {
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
Hi I have a app that follow as follow: MainActivity use navigationDrawer to navigate between fragment for example fragment1, fragment2, fragment3. Fragment1 Contain tablayout fragment1-A and child fragment1-B and fragment1-C. when user in fragment1-B click a button, they will go to another fragment1-B-a (this transaction will be add to backstack). When user press backButton in fragment1-B-a. They will go back to fragment1-B by these code in the MainActivity.
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
// if got BackStack, come back to it
if (fragmentManager.getBackStackEntryCount()>0) {
super.onBackPressed();
// if not come to home screen
}else {
if (!homeFlag) {
fragment = new MainFragment();
fragmentManager.popBackStack();
fragmentManager.beginTransaction().replace(R.id.contentMainDrawer, fragment).commit();
homeFlag = true;
} else exit();
}
}
}
But when user inside fragment1-B-a (2nd tablayout fragment) if they press BackButton. It give the error and crash the app (inside fragment1-B-a press backButton work normally)
this is the error. Anyhelp is much appreciate. Thanks.
12-31 12:20:22.118 9719-9719/victory1908.nlbstafflogin2 E/AndroidRuntime: FATAL EXCEPTION: main
Process: victory1908.nlbstafflogin2, PID: 9719
java.lang.IndexOutOfBoundsException: Invalid index 1, size is 0
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at android.support.design.widget.TabLayout.getTabAt(TabLayout.java:448)
at android.support.design.widget.TabLayout$TabLayoutOnPageChangeListener.onPageSelected(TabLayout.java:1759)
at android.support.v4.view.ViewPager.dispatchOnPageSelected(ViewPager.java:1794)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:548)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:514)
at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1320)
at android.view.View.dispatchRestoreInstanceState(View.java:14564)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3157)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3163)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3163)
at android.view.View.restoreHierarchyState(View.java:14542)
at android.support.v4.app.Fragment.restoreViewState(Fragment.java:468)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1094)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
at android.support.v4.app.BackStackRecord.popFromBackStack(BackStackRecord.java:958)
at android.support.v4.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1666)
at android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:586)
at android.support.v4.app.FragmentActivity.onBackPressed(FragmentActivity.java:169)
at victory1908.nlbstafflogin2.MainActivity.onBackPressed(MainActivity.java:134)
at android.app.Activity.onKeyUp(Activity.java:2550)
at android.view.KeyEvent.dispatch(KeyEvent.java:3159)
at android.app.Activity.dispatchKeyEvent(Activity.java:2805)
at android.support.v7.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:50)
at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent(AppCompatDelegateImplBase.java:224)
at android.support.v7.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:50)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2429)
at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4508)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4463)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4020)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4073)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4039)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4153)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4047)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4210)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4020)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4073)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4039)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4047)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4020)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4073)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4039)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4186)
at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:4347)
at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2480)
at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:2074)
at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:2065)
at android.view.inputmetho
Store fragment name is public static variable lastFragment...
update it whenever moving to new fragment by setting its previous fragment ....
make it null in main activity ...
-exit app if it is null otherwise replace fragmentmanger with lastFragment.
Ok. I got your problem. This is because getBackStackEntryCount() is returning Zero.
So you need to add below lines after committing your fragment onBackPressed Button.
fragmentManager.executePendingTransactions();
and add
fragmentManager(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) instead of fragmentManager.popBackStack();
FragmentManager.POP_BACK_STACK_INCLUSIVE) is usedto pop the entire back stack.
See this discussion
Editing in your code :
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
// if got BackStack, come back to it
if (fragmentManager.getBackStackEntryCount()>0) {
super.onBackPressed();
// if not come to home screen
}else {
if (!homeFlag) {
fragment = new MainFragment();
fragmentManager(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)// Change
fragmentManager.beginTransaction().replace(R.id.contentMainDrawer, fragment).commit();
fragmentManager.executePendingTransactions();// Change
homeFlag = true;
} else exit();
}
}
}
Hope it help you.
I am using a DrawerLayout with and adding a new Fragment each time the user taps an item from the drawer menu. This works perfectly.
Within one of those fragments the user can navigate to another fragment:
private void loadArchives() {
PUCNewsArchive news_archive = new PUCNewsArchive();
getFragmentManager()
.beginTransaction()
.add(R.id.container_frame, news_archive, "news_archives")
.addToBackStack(null)
.commit();
}
This will correctly add another fragment to the stack. BUT, it does not change the action bar drawer button/icon to a back button. So, in tapping that just opens the drawer again, which is should not do. The only way to navigate back is the use the hardware back button which does go back to the previous fragment. I tried adding the following to my main Activity to see what was going on:
#Override
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack();
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed();
}
}
But that is only ever called when I use the hardware back button, as the drawer button is only ever opening the drawer.
I assume this should be checking to see if it should open the drawer or navigate:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
switch(item.getItemId()) {
case android.R.id.home:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
What have I missed? Why is the drawer button never changing to a back button nor acting like one?
You don't need to use the onBackPressed().
I had a very similar situation in my app. Here is how I got it to work:
I created a method in the main activity:
public void foo(int fragment_id) {
if(fragment_id == some_id){
// keep the drawer carat
mDrawerToggle.setDrawerIndicatorEnabled(true);
}else{
// Disable the drawer carat, and enable the back button
mDrawerToggle.setDrawerIndicatorEnabled(false);
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
I call this method from onResume() of each fragment, and pass it that particular fragments id. Alternatively, you can call it from the loadFragment()/loadArchives() method in your main activity. This works fine for me.
In your Navigation Activity
This activity controls all fragments in the app.
When preparing new fragments to replace others, I set the DrawerToggle
setDrawerIndicatorEnabled(false) like this:
private void loadArchives() {
PUCNewsArchive news_archive = new PUCNewsArchive();
//disable the toggle menu and show up carat
theDrawerToggle.setDrawerIndicatorEnabled(false);
getFragmentManager()
.beginTransaction()
.add(R.id.container_frame, news_archive, "news_archives")
.addToBackStack(null)
.commit();
}
in onCreateview of another fragment
call
// update the actionbar to show the up carat/affordance
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
For More reference Check This Question
I tried above suggested codes But the "up" or "Back" arrow in left side of action bar was just not showing up in my app. But luckily I was able to fix that.
Brief code:
Function to start fragment while putting the current fragment to Back Stack:
public void startFragment(){
MyFrag myFrag = new MyFrag();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frag_container ,myFrag)
.addToBackStack(null)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit();
}
Function to turn ON or OFF "NavigationDrawer":
public void setNavigationDrawerState(boolean isEnabled) {
if ( isEnabled ) {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
toggle.setDrawerIndicatorEnabled(true);
toggle.syncState();
}
else {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
toggle.setDrawerIndicatorEnabled(false);
toggle.setHomeAsUpIndicator(R.drawable.ic_keyboard_backspace_white_24dp);
toggle.syncState();
}
I downloaded the drawable: ic_keyboard_backspace_white_24dp from Material.io
The complete answer:
Disabling navigation drawer, toggling home-button/up-indicator in fragments
I am working with the navigation drawer, and having a small problem. The problem occurs When I am in my an activity, and navigate to that same activity though the navigation drawer. The activity launches new (screen popping up).
I would like the drawer to just close when the user attempts to navigate to the activity they are currently on.
Thanks for you help!
Why not just check the current Activity, pseudocode:
if (this instanceof SomeActivity){
closedrawer();
}else{
navigate to SomeActivity
}
//global reference
private DrawerLayout mDrawerLayout;
//instantiate onCreate()
mDrawerLayout= (DrawerLayout) findViewById(R.id.drawer_layout);
//close it some where, on button click...
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
mDrawerLayout.closeDrawer(Gravity.LEFT);
}
In the method you handle clicks from the navigation drawer:
// This is for the case where the user is trying to open a fragment called `NewFragment`
Fragment currentFragment = getSupportFragmentManager().findFragmentByTag(NewFragment.TAG);
if (currentFragment == null) {
NewFragment newFragment = new NewFragment()
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment, NewFragment.TAG);
transaction.commit();
}
mDrawerLayout.closeDrawer(mDrawerList);
This works if you have added your fragments to the fragment container with the tag. I usually keep this as a public static final String in the respective fragments. For instance, NewFragment has a static String called TAG that is can be used to find it later using the fragment manager.
If the currentFragment is null, it means that is not currently added to the manager's activity nor on the back stack. In that case add the new fragment to the fragment container. If not, just simply close the navigation drawer.