popBackStack() not working properly - android

When I open a fragment from BottomNavigationBar, it opens perfectly. When I press back button, previous fragment opens but state of BottomNavigationBar does not change.
As in my screenshots, when i backpressed from Account fragment, Home fragment opens but state of BottomNavigationBar has not been changed.
Screenshot 1 - https://drive.google.com/file/d/12cDvhwO1jpG2A1PUsfHQGProqx2cT6Bp/view
Screenshot 2 - https://drive.google.com/file/d/1Zws5sMJeXxts6k6IEBGUGyJYfZP58Czs/view
btnNavBar.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_item1:
loadFragment(fragmentManager, new HomeFragment(), "Home");
break;
case R.id.action_item2:
loadFragment(fragmentManager, new SearchFragment(), "Search");
break;
case R.id.action_item3:
loadFragment(fragmentManager, new AccountFragment(), "Account");
break;
}
return true;
}
});
public static void loadFragment(FragmentManager fragmentManager, Fragment fragment, String tag) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frameLayoutContainer, fragment);
fragmentTransaction.commit();
}

I suggest you to not add the fragments to the back stack because it's not the expected behaviour for the Android users. The bottom bar is here to show 3 to 5 different destinations to the user (for example, a news feed, a user profile, etc.). When you select a tab, you should just change the current fragment (and not create a fragments stack). The back button should only close the app, or re-open the previous screen if there is one (definitely not re-open the previous tab :) ). I suggest you to look at this Material Design guidelines for BottomNavigationBar.

Related

MeowBottomNavigation issue - need to select menu from fragmentLoad() method in mainActivity

I am using MeowBottomNavigation and from one fragment, I need to redirect to another fragment. but when I am doing that, the navbar displays the old menu selection.
Please help me.
This is on Home Fragment
enter image description here
Now, its displaying data from 2nd fragment but nav shows HOME only. Ti should be 2nd nav.
enter image description here
CODE
getSupportFragmentManager().beginTransaction().replace(R.id.framelayout, fragment).commit();
bottomNavigation = findViewById(R.id.bottomNav);
bottomNavigation.add(new MeowBottomNavigation.Model(1, R.drawable.ic_nav_home));
bottomNavigation.add(new MeowBottomNavigation.Model(2, R.drawable.ic_baseline_category_24));
bottomNavigation.setOnShowListener(new MeowBottomNavigation.ShowListener(){
#Override public void onShowItem(MeowBottomNavigation.Model item) {
Fragment fragment = null;
switch (item.getId()){
case 1: fragment = new HomeFragment(); break;
case 2: fragment = new CategoryFragment(); break;
}
fragmentLoad(fragment);
}
});
bottomNavigation.show(1, true);
}
public void fragmentLoad(Fragment fragment) {}

Android Show Hide Fragment BottomNavigationView First Added Item Not Visible

I have a setup of 3 Fragments inside my main activity and want to navigate them using the BottomNavigationView. I want to add them once and then just switch between them without actually destroying the Fragments. Everything works fine except that the first fragment added to the SupportFragmentManager always disappears (tried changing the order so the problem is not with the Fragments themselves). Actually, it doesn't disappear but the last Fragment that occupied the container shows up.
Eg. I go to position 3, Fragment 3 shows up in the container and then click on position 1, Fragment 3 will still occupy the container. But if I tap position 2 Fragment 2 will appear. How I'm adding the Fragments:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.container, fragment1); //whatever gets added here ends up being invisible
ft.commitAllowingStateLoss();
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.container, fragment2);
ft.commitAllowingStateLoss();
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.container, fragment3);
ft.commitAllowingStateLoss();
How I'm switching between them using the OnNavigationItemSelectedListener:
private BottomNavigationView.OnNavigationItemSelectedListener navigation_listener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
Fragment previousFragment = getSupportFragmentManager().findFragmentById(R.id.container);
switch(item.getItemId()){
case R.id.bottom_navigation_bar_position1:
selectedFragment = fragment1;
break;
case R.id.bottom_navigation_bar_position2:
selectedFragment = fragment2;
break;
case R.id.bottom_navigation_bar_position3:
selectedFragment = fragment3;
break;
}
getSupportFragmentManager().beginTransaction().hide(previousFragment).commit();
getSupportFragmentManager().beginTransaction().show(selectedFragment).commit();
return true;
}
};
The XML menu navigation:
<item
android:id="#+id/bottom_navigation_bar_position1"
android:title="Title1"
android:icon="#drawable/ic1"
/>
<item
android:id="#+id/bottom_navigation_bar_position2"
android:title="Title2"
android:icon="#drawable/ic2"
/>
<item
android:id="#+id/bottom_navigation_bar_position3"
android:title="Title3"
android:icon="#drawable/ic3"
/>
Btw. just using replace() instead of show and hide works but that's not the goal...
I've also tested whether the first added Fragment exits (and doesn't get destroyed) and it indeed exists...
Thanks!
Instead of trying to show and hide fragment I solved the problem by managing the Fragments using a ViewPager and a SectionsPageAdapter. Once you link these two, use ViewPager.setOffscreenPageLimit(3) to make sure no Fragments get destroyed. My BottomNavigationView.OnNavigationItemSelectedListener looks like this now:
private BottomNavigationView.OnNavigationItemSelectedListener navigation_listener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch(item.getItemId()){
case R.id.bottom_navigation_bar_position1:
tab_view_pager.setCurrentItem(0);
return true;
case R.id.bottom_navigation_bar_position2:
tab_view_pager.setCurrentItem(1);
return true;
case R.id.bottom_navigation_bar_position3:
tab_view_pager.setCurrentItem(2);
return true;
}
return false;
}
};
You have to set 0th position item selected for BottomNavigationView.OnNavigationItemSelectedListener. Find Menu bottom_navigation_bar_position1
I used this in my code, please refactor according to your needs
BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(this);
Menu menu = navigation.getMenu();
this.onNavigationItemSelected(menu.findItem(R.id.navigation_doc));

Correct Activity/Fragment Architecture for Android Bottom Navigation View

I would like to get some input on the best way to structure my app's architecture when using Android's Bottom Navigation View.
Currently I define my BottomNavigationView in my MainActivity. It looks something like this.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView bottomNavigationView = (BottomNavigationView)findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()){
case R.id.action_home:
selectedFragment = HomeFragment.newInstance();
break;
case R.id.action_search:
selectedFragment = SearchFragment.newInstance();
break;
case R.id.action_message:
selectedFragment = MessageFragment.newInstance();
break;
case R.id.action_profile:
selectedFragment = ProfileFragment.newInstance();
break;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, selectedFragment);
transaction.commit();
return true;
}
});
//Manually displaying the first fragment - one time only
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, HomeFragment.newInstance());
transaction.commit();
}
The problem is that once I click on one tab, it opens up a fragment, and I would like to have those Fragments open up other Fragments/Activities (i.e:
I open the profile tab (`ProfileFragment` loads)
I click on a button from `ProfileFragment`, and from this the `SignUpFragment` or `SignUpActivity` loads
After running into many bugs, I've researched on how to architect my app, but i've found mixed results. Would anyone know the correct way of using a BottomNavigationView with Fragments, and in those fragments I can load more Activities/fragments. A huge thanks in advance.
Every approach depends on the project and what you pretend to achieve. I had to code a Bottom Navigation app that works with over 20 Bottom Navigation layouts, meaning one single Activity. The process you wish to achieve is pretty much the same of setting the desired fragment in the desired tab on tab selected, the difference is that, instead of taping on a tab, you will tap on a button inside a fragment, which you will replace with the new desired fragment.
tap tab -> replace fragment -> button click inside fragment -> replace fragment -> and so on.
Since you are using replace, you will have to carefully handle your onBackPress event, since I'm assuming that on every back press you wish to go back to the previous fragment. Myself, I've implemented an interface in the Main Activity that listens to the visible fragment onBackPress.

How to remove all fragments except first one?

My application contains AppBaseActivity having NavigationView with few menu items. By default, I load Home fragment & on clicking each menu item from drawer, I open specific fragment.
My problem is, I need keep Home fragment all the time showing if user clicks back button.
Stepwise explanation :
On activity launch, loads Home fragment by default
Suppose selects Menu Item 1, loads related fragment[*4]
Suppose selects Menu Item 2, loads related fragment[*4]
I want to make back stack clear however, keeping Home fragment persistent so that if user presses back button instead of opting menu item from drawer or simply go to any fragment & on killing it, should navigate back to Home fragment.
In my current case, it simply closes/terminates my app.
AppBaseActivity Java (some part of code)
onCreate() {
fragmentTransaction = fragmentManager.beginTransaction();
HomeFragment homeFragment = new HomeFragment();
fragmentTransaction.add(R.id.body_container, homeFragment, getResources().getString(R.string.app_name));
fragmentTransaction.commit();
}
#SuppressWarnings("StatementWithEmptyBody")
#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 :
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentTransaction = fragmentManager.beginTransaction();
TCFragment tcFragment = new TCFragment();
fragmentTransaction.add(R.id.body_container, tcFragment, getResources().getString(R.string.tc_screen_name));
fragmentTransaction.commit();
break;
case R.id.nav_about_us :
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentTransaction = fragmentManager.beginTransaction();
AboutUsFragment aboutUsFragment = new AboutUsFragment();
fragmentTransaction.add(R.id.body_container, aboutUsFragment, getResources().getString(R.string.about_us_screen_name));
fragmentTransaction.commit();
break;
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
try by adding this line with home fragment before commit:
fragmentTransaction addTobackStack(null);
You need to add the transaction to the backstack using addToBackStack(). The back press would automatically pop the topmost fragment from the backstack.
Refer to
https://developer.android.com/guide/components/fragments.html
The relevant section is "Performing Fragment Transactions"

prevent same fragment multiple times in backstack

Hi guys here is my code
navigationView.setNavigationItemSelectedListener(new NavigationView
.OnNavigationItemSelectedListener() {
#Override public boolean onNavigationItemSelected(#NonNull MenuItem item) {
if (item.isChecked()) {
//item already selected. Do nothing
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
switch (item.getItemId()) {
case R.id.home:
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.fragment, new HomeFragment())
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE).commit();
break;
case R.id.other:
transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, new OtherFragment())
.addToBackStack(null).setTransition(FragmentTransaction
.TRANSIT_FRAGMENT_FADE).commit();
break;
default:
break;
}
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
});
I basically only have 2 fragments and merely the HomeFragment should be added to the backstack. After switching between HomeFragment and OtherFragment for a while and clicking on the back button while on the HomeFragment, I end up with the HomeFragment getting displayed several times.
Within the HomeFragment lies a recyclerview. When I scroll up and down I can really see that the rows are displayed multiple times.
How can I make sure that the HomeFragment is added to the backstack only once.
Thanks
You could easily check your fragment with
YourFragment.isAdded
And if you have a multiple fragment you could create a new class to manage all the fragment and create state to check if fragment have been added or not.
When you click on the Home menu item try to find out whether there is any fragment in the backstack or not. If yes, call popBackStack() or replace a fragment as you do now otherwise. Use this code: if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
}

Categories

Resources