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

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) {}

Related

popBackStack() not working properly

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.

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.

Accessing the same Fragment in Navigation Drawer clears its content

I have Fragment A that lets the user access Fragment B by the click of a button, when an action is performed on B, user is redirected to Fragment C to retrieve a last bit of information before returning to A.
(A -> B -> C -> A).
After doing this, if I open my Navigation Drawer and click on the Fragment I am currently on (A), its contents are gone, only the Drawer itself remains.
I can't seem to explain the reason behind this.
Here is how I conserve my Navigation Drawer's Fragment states:
// User clicks on an item in Nav. Drawer, call this method
private Fragment checkFragmentState(int itemId) {
Fragment fragment = null;
switch (itemId) {
// HOME
case R.id.nav_home:
if (home == null) {
fragment = new Home();
home = fragment;
} else
fragment = home;
break;
// SEARCH CARD
case R.id.nav_searchCard:
if (searchCard == null) {
fragment = new SearchCard();
searchCard = fragment;
} else
fragment = searchCard;
break;
}
return fragment;
}
I call this method when my user clicks on an element in the Drawer, basically it checks if the Fragment has already been created, if so, it saves the currently existing one and uses it to be displayed.
What could cause this odd behavior?
Just launch a new instance each time
// User clicks on an item in Nav. Drawer, call this method
private Fragment checkFragmentState(int itemId) {
Fragment fragment = null;
switch (itemId) {
case R.id.nav_home:
fragment = new Home();
break;
case R.id.nav_searchCard:
fragment = new SearchCard();
break;
default:
fragment = new Fragment();
}
return fragment;
}

Handling fragment backstack in Navigation drawer

okay i know there are other questions that on first glance make this one look like a duplicate, but none of these answers work in my case,
What i want is the first fragment displayed to be like a Main Activity in respect to how the back button works, i need whichever fragment i choose from my navigation drawer to go back to the first fragment when the back button is pressed then a user would quit the app by pressing it again.
So ive tried using addToBackStack and when i move to another fragment if i press the back button it comes back to my first fragment (exactly as i want) but pressing the back button again leaves me with a white screen (i wonder if this is due to the transaction animation im using which ive included below) so to get around this i tried overriding the back button and throwing in a call to finish(); but this causes whichever fragment im in to finish instead of going back to the first fragment, ive tried a handful of workarounds from the above mentioned link and many others but cannot find a decent fix any suggestions?
here is my Main Activity displayView
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new FirstFragment();
break;
case 1:
fragment = new glideFrag();
break;
case 2:
fragment = new secondGlideFrag();
break;
case 3:
fragment = new thirdGlideFrag();
break;
case 4:
fragment = new forthGlideFrag();
break;
case 5:
fragment = new lgFrag();
break;
case 6:
fragment = new cyanFrag();
break;
case 7:
fragment = new sonyFrag();
break;
case 8:
fragment = new SecondFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.enter,R.anim.exit,R.anim.pop_enter,R.anim.pop_exit);
//fragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.frame_container, fragment).addToBackStack("first Fragment").commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
i found this that looks like a great way around it
private boolean popNext = false;
if(popNext){
if(position == INITIAL_POSITION){
onBackPressed();
mDrawerLayout.closeDrawer(mDrawerList);
popNext = false;
return;
}
getSupportFragmentManager().popBackStackImmediate();
}
else{
if(position == INITIAL_POSITION){
mDrawerLayout.closeDrawer(mDrawerList);
return;
}
popNext=true;
}
but im still fairly new to android and im not sure what to set INITIAL_POSITION to, I tried
private static final INITIAL_POSITION = 0;
but without any luck
When adding the initial fragment, you must not add it to the back stack.
You must only do it for the next ones. When the back stack will be empty, the Activity will just finish.
Edit: Here is an explanation of the problem so you can figure out how to fix it:
Each time you add a fragment transaction to the back stack, you allow the user to revert it by pressing the back button and the Activity will return to the state it was before the transaction. If the initial fragment is added to the back stack, then when the user press back, the screen becomes blank, because there was nothing displayed before you added the initial fragment. That's why the initial fragment transaction which adds the first visible fragment to your Activity must not be added to the back stack. Usually you initialize the initial fragment like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null) {
Fragment fragment = new FirstFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.frame_container, fragment)
.commit();
}
}
BladeCoders answer was more trying to tell me how the backstack works rather than answering my question, i ended up not adding any fragments to the back stack, .addToBackStack(null), and overriding back button in MainActivity, feels like a little bit of a hack but works perfectly
#Override
public void onBackPressed() {
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() < 1){
Fragment fragment = new FirstFragment();
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.enter, R.anim.exit,
R.anim.pop_enter, R.anim.pop_exit);
getSupportActionBar().setTitle(mDrawerTitle);
fragmentTransaction.replace(R.id.frame_container,
fragment).addToBackStack("first").commit();
}else{
finish();
}
}
You can do it even with out backstack its just my point of view to simplify so that it can help some one.
#Override
public void onBackPressed(){
Fragment f = getSupportFragmentManager().findFragmentById(R.id.container_body);
if(f.getClass().getName().equals(HomeFragment.class.getName())){ // here HomeFragment.class.getName() means from which faragment you actually want to exit
finish();
}else{
displayView(0); //were you want to go when back button is pressed
}
}
private void displayView(int position) {
Fragment fragment = null;
String title = getString(R.string.app_name);
switch (position) {
case 0:
fragment = new HomeFragment();
title = getString(R.string.app_name);
break;
case 1:
fragment = new OffersFragment();
title = getString(R.string.nav_item_offers);
break;
case 2:
fragment = new NotificationFragment();
title = getString(R.string.nav_item_notifications);
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container_body, fragment);
fragmentTransaction.commit();
// set the toolbar title
getSupportActionBar().setTitle(title);
}
}

Android IllegalStateException: Fragment already active when calling notifyDataSetChanged

I'm new to Android, and looks like there are still some things missing in my understanding of the activity lifecycle. I have a tabbed application created with a FragmentActivity. A custom ViewPager is managing the presentation of tabs and in one of those tabs I want a simple drill-down with the ability to use the hardware "Back" button to go back up a level to the previous view.
I implemented this drill-down by just substituting an appropriate Fragment into the tab by checking the value of a flag (which determines where in the drill down we are):
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
#Override
public Fragment getItem(int position) {
Fragment fragment;
switch (position) {
case 0 :
if (stateFlag == 0) fragment = (Fragment) new InitialFragment();
else fragment = (Fragment) new FinalResultsFragment();
break;
case 1:
fragment = (Fragment) new SecondTabFragment();
break;
default:
fragment = (Fragment) new ThirdTabFragment();
break;
}
return fragment;
}
To go back to the "previous" Fragment I do this:
#Override
public void onBackPressed() {
int p = mViewPager.getCurrentItem();
switch (p) {
case 0:
if (stateFlag == 0)) {
super.onBackPressed();
} else {
stateFlag = 0;
mViewPager.getAdapter().notifyDataSetChanged();
mViewPager.setCurrentItem(0);
}
break;
default:
super.onBackPressed();
break;
}
}
This works fine, until I try changing the orientation. The Fragments come back from that change successfully, but when I try pressing the Back button while in the FinalResultsFragment state, I get
IllegalStateException: Fragment already active
E/AndroidRuntime(1094): at android.support.v4.view.PagerAdapter.notifyDataSetChanged(PagerAdapter.java:276)
Why is the change in orientation breaking this particular part of the code?
Edit:
So if I open the app, first tab active, I press a button that loads a different fragment in that tab, then press the Back button - it's all good and the first fragment is loaded, as expected.
But if I open the app, first tab active, I press a button that loads a different fragment in that tab, the rotate the screen, the fragment is re-loaded just fine, then press the Back button - crash!
Edit:
here is the complete error log: http://pastebin.com/ESDTstsm

Categories

Resources