Tobias Alt
Tobias Alt

Reputation: 483

Going mad with Android Fragment Transaction

I can not comprehend this behavior of my fragment transactions. Can someone please intervent before I go crazy. In my MainActivity I set it up correctly:

    private final GuideFragment guideFragment = new GuideFragment();
    private final MapFragment mapFragment = new MapFragment();
    private final MoreFragment moreFragment = new MoreFragment();

    Fragment active;

    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
                = new BottomNavigationView.OnNavigationItemSelectedListener() {

            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                FragmentTransaction transaction = getFragmentManager().beginTransaction();
                switch (item.getItemId()) {
                    case R.id.navigation_guide:
                        if (!guideFragment.isAdded()) {
                            transaction.add(R.id.content,guideFragment).commit();
                            active = guideFragment;
                            Log.d(TAG, "add Fragment1");
                            break;
                        } else {
                            transaction.hide(active).show(guideFragment).commit();
                            active = guideFragment;
                            Log.d(TAG, "show Fragment1");
                            break;
                        }
                    case R.id.navigation_map:
                        if (!mapFragment.isAdded()) {
                            transaction.add(R.id.content, mapFragment).commit();
                            active = mapFragment;
                            Log.d(TAG,"add Fragment2");
                            break;
                        } else {
                            transaction.hide(active).show(mapFragment).commit();
                            active = mapFragment;
                            Log.d(TAG,"show Fragment2");
                            break;
                        }
                    case R.id.navigation_more:
                        if (!moreFragment.isAdded()) {
                            transaction.add(R.id.content,moreFragment).commit();
                            active = moreFragment;
                            Log.d(TAG,"add Fragment3");
                            break;
                        } else {
                            transaction.hide(active).show(moreFragment).commit();
                            active = moreFragment;
                            Log.d(TAG,"show Fragment3");
                            break;
                        }
                }

                return true;
            }

        };

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_start);

        //start with guide view/fragment
        switchTabView(R.id.navigation_guide);

    }

    //method to start or switch a tab
    private void switchTabView(int itemId) {
        navigation = (BottomNavigationView) findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
        navigation.setSelectedItemId(itemId);

    }

My App has 3 Tabs as you can see above: Tab1 (Guide) Tab2 (Map) Tab3 (More).

When the app launches, the first Tab (Guide) is added and shown correctly. Then I tap on Map (next Fragment), this is added and shown correctly. Finally on the More Tab (my 3rd Tab) all works great.

But when the activity launches and I tap 1-3 (Guide to Map) so far correct - then 3-2 (More Tab to Map Tab) all good - but then back from 2-1 (Map to Guide) there is suddenly the 3rd tab Fragment (More) shown where the Guide Fragment should be.

Someone has an idea on what is wrong? Would appreciate some help.

Solution thanks to Mateus

transaction.hide(fragment3).hide(fragment2).show(fragment1).commit();

I am not sure if calling two times hide fragment is that clean but I think with 3 tabs it is still okay. With more tabs I would consider to handle this in a different way like remove() or replace() fragments.

Update - Solution is more tricky as expected:

           switch (item.getItemId()) {
                case R.id.navigation_guide:
                    if (!guideFragment.isAdded()) {
                        transaction.add(R.id.content,guideFragment).commit();
                        Log.d(TAG, "add Fragment1");
                        break;
                    } else {
                        if (!moreFragment.isAdded() && mapFragment.isAdded()) {
                            transaction.hide(mapFragment).show(guideFragment).commit();
                        }
                        if (moreFragment.isAdded() && !mapFragment.isAdded()) {
                            transaction.hide(moreFragment).show(guideFragment).commit();
                        }
                        if (moreFragment.isAdded() && mapFragment.isAdded()) {
                            transaction.hide(moreFragment).hide(mapFragment).show(guideFragment).commit();
                        }

                        Log.d(TAG, "show Fragment1");
                        break;
                    }
                case R.id.navigation_map:
                    if (!mapFragment.isAdded()) {
                        transaction.add(R.id.content, mapFragment).commit();
                        Log.d(TAG,"add Fragment2");
                        break;
                    } else {
                        if (!moreFragment.isAdded()) {
                            transaction.hide(guideFragment).show(mapFragment).commit();
                        } else {
                            transaction.hide(guideFragment).hide(moreFragment).show(mapFragment).commit();
                        }
                        Log.d(TAG,"show Fragment2");
                        break;
                    }
                case R.id.navigation_more:
                    if (!moreFragment.isAdded()) {
                        transaction.add(R.id.content,moreFragment).commit();
                        Log.d(TAG,"add Fragment3");
                        break;
                    } else {
                        if (!mapFragment.isAdded()) {
                            transaction.hide(guideFragment).show(moreFragment).commit();
                        } else {
                            transaction.hide(guideFragment).hide(mapFragment).show(moreFragment).commit();
                        }
                        Log.d(TAG,"show Fragment3");
                        break;
                    }
            }

Finally bug free, you have to check if other fragments are added!

Upvotes: 2

Views: 771

Answers (2)

S.Sapakos
S.Sapakos

Reputation: 11

When I want to go to another fragment in the same activity I use this:

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

transaction.replace(R.id.container,yourFragment);
transaction.commit();

Container is a layout in your activity. Use it to show your fragment. Also you have to init in each case of bottomNavigationView the FragmentTransaction object!

I believe that this is what you are looking for!

Upvotes: 1

Mateus Gondim
Mateus Gondim

Reputation: 5532

At the point you go back from 2 to 1, this line will be called:

transaction.hide(active).show(guideFragment).commit();

The problem is that when you hide active(Fragment 2) and show Fragment 1, Fragment 3(which was added after Fragment 1, therefore is "on top" of Fragment1) is still being shown. You'd have to call hide on Fragment 3 too to see Fragment 1.

In other words, you need to adjust your code to hide all the other fragments everytime you want to show a specific one.

Also check this discussion about choosing between show/hide and add/remove/replace to confirm that the first strategy better suits your needs.

Upvotes: 3

Related Questions