0

I have something like this inside my activity:

@Override
    public void onNavigationDrawerItemSelected(int position) {
        Fragment fragment = null;
        switch (position+1) {
            case 1: {
                fragment = new Fragment_Login();
                FragmentManager frgManager = getFragmentManager();
                frgManager.beginTransaction().replace(R.id.container, fragment)
                        .commit();
                break;
            }
            case 2: {
                SwipeRefreshListFragment swipeFragment = new Fragment_List_Of_Assessments();
                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.container, swipeFragment)
                        .commit();
                break;
            }
            case 3: {
                fragment = new Fragment_Report();
                FragmentManager frgManager = getFragmentManager();
                frgManager.beginTransaction().replace(R.id.container, fragment)
                        .commit();
                break;
            }
            case 4: {
                fragment = new Fragment_Settings();
                FragmentManager frgManager = getFragmentManager();
                frgManager.beginTransaction().replace(R.id.container, fragment)
                        .commit();
                break;
            }
            default:
                break;
        }
    }

The program automatically loads case1, but when case2 is selected, getSupportFragmentManager loads the Fragment on top of case1. I guess there are some problem with using both supportFragmentManager and FragmentManager. They seem to have their own stack. The problem is that I cannot use only either one of them because the SwipeToRefresh Android example uses ListView which needs support.v4.Fragment which needs the old FragmentManager. So how is it possible to integrate both FragmentManagers together?

MANOJ GOPI
  • 1,279
  • 10
  • 31
holyxiaoxin
  • 690
  • 1
  • 7
  • 26
  • Just use the `android.support.v4.Fragment` class for all of your `Fragments` and things will be much easier for you. Pretty much anything in the support libs will be based on support `Fragments`. – Kevin Coppock Jan 27 '15 at 05:18
  • But the problem is that I've implemented methods that supportfragment does not support. :/ I wish to still keep and use only fragment instead of supportfragment. Is that possible? – holyxiaoxin Jan 27 '15 at 05:20
  • Not if you want to use features from the support library. What have you implemented in native fragments that you can't do with the support fragments? For the most part, migration should just be changes in imports. – Kevin Coppock Jan 27 '15 at 05:21

3 Answers3

4

I have accomplished something like this when using PreferenceFragment (not supported by support library version). In order to achieve this I kept inside my Activity a pair of boolean (isLastFragmentSupportType and lastFragmentShowed) and also a String (lastFragmentTag).

At the beginning your Activity will have both of them to false. And when you add a new Fragment you use these 2 boolean to know if you need to clean the other FragmentManager or not. I'll use your code as an example:

@Override
public void onNavigationDrawerItemSelected(int position) {
    Fragment fragment = null;
    switch (position+1) {
        case 1: {
            if(isLastFragmentSupportType && lastFragmentShowed)
            {//As your last fragment  was a support type you need to clear your supportFragmentManager
              android.support.v4.app.Fragment fr_v4 = getSupportFragmentManager().findFragmentByTag(lastFragmentTag);
               getSupportFragmentManager().beginTransaction().remove(fr_v4).commit();
            }
            fragment = new Fragment_Login();
            FragmentManager frgManager = getFragmentManager();
            frgManager.beginTransaction().replace(R.id.container, fragment,TAG1)
                    .commit();
          lastFragmentTag = TAG1;
          lastFragmentShowed = true;
          isLastFragmentSupportType = false; 
            break;
        }
       //And so on with the others

You need to check what type (support or not) of fragment you are going to use, and check these variables to see if the last fragment was of a different type. If that is the case clean the other fragmentmanager to "clear" the screen so they wont overlap.

Also use TAGS to identify and retrieve your current fragments so you do not need to have Fragment variables over your code.

Finally use onSavedInstanceState so as to keep these values in case you need them.

Hope it helps :)

zozelfelfo
  • 3,776
  • 2
  • 21
  • 35
  • But by doing this I assume you can use the back button to perform a popstack on the fragment manager? – holyxiaoxin Jan 27 '15 at 08:01
  • If you are using different fragment managers and you use back button, you MAY perform popstack on your current fragment manager, if your last fragment was into the other fragment manager you will not simply get it, I would recommend you to handle `onBackPressed` on your own – zozelfelfo Jan 27 '15 at 08:24
  • Sounds abit hackish. But I guess it'll work. Thanks. (: – holyxiaoxin Jan 27 '15 at 08:31
1

This answer is inspired from answer by zozelfelfo. Use these two methods to replace fragments instead of getFragmentManager.beginTransaction.replace...

private void replaceFragment(Fragment fragment, String fragmentTag) {
    if(lastFragmentShowed && isLastFragmentSupportType) {
        android.support.v4.app.Fragment fr_v4 = getSupportFragmentManager().findFragmentByTag(lastFragmentTag);
        getSupportFragmentManager().beginTransaction().remove(fr_v4).commit();
    }
    getFragmentManager().beginTransaction()
            .replace(R.id.fragment_container, fragment, fragmentTag)
            .commit();
    lastFragmentTag = fragmentTag;
    lastFragmentShowed = true;
    isLastFragmentSupportType = false;
}

private void replaceFragment(android.support.v4.app.Fragment fragment, String fragmentTag) {
    if(lastFragmentShowed && !isLastFragmentSupportType) {
        Fragment fr = getFragmentManager().findFragmentByTag(lastFragmentTag);
        getFragmentManager().beginTransaction().remove(fr).commit();
    }
    getSupportFragmentManager().beginTransaction()
            .replace(R.id.fragment_container, fragment, fragmentTag)
            .commit();
    lastFragmentTag = fragmentTag;
    lastFragmentShowed = true;
    isLastFragmentSupportType = true;
}
penduDev
  • 4,743
  • 35
  • 37
0

I'm using BottomNavigationView as Tab Bar and switching fragments as tabs. All but one fragment are Support Fragments (and last one is PreferenceFragment). I'm using "hide-add-show" rather than "remove-replace". So, status of fragments in other tabs can be preserved.

Original function to switch:

private Fragment lastFragment = null;
private void switchFragment(Fragment fragment) {
    if (lastFragment != fragment) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (null != lastFragment) {
            transaction.hide(lastFragment);
        }
        lastFragment = fragment;
        if (!fragment.isAdded()) {
            transaction.add(R.id.fragment_container, fragment);
        }
        transaction.show(fragment).commitAllowingStateLoss();
    }
}

I don't use tag nor boolean, just want to keep a reference to last fragment object. So, when switching, just call switchFragment() with instance of any fragment:

private Object lastFragment = null;
private void switchFragment(Object fragment) {
    if (lastFragment != fragment) {
        if (null != lastFragment) {
            if (lastFragment instanceof android.support.v4.app.Fragment) {
                hideFragment((android.support.v4.app.Fragment) lastFragment);
            } else if (lastFragment instanceof android.app.Fragment) {
                hideFragment((android.app.Fragment) lastFragment);
            }
        }
        lastFragment = fragment;
        if (fragment instanceof android.support.v4.app.Fragment) {
            showFragment((android.support.v4.app.Fragment) fragment);
        } else if (fragment instanceof android.app.Fragment) {
            showFragment((android.app.Fragment) fragment);
        }
    }
}

So, this function still do the same things but switch between Support Fragment and Native Fragment by checking the target class. Helper functions:

// Support Version:
private void hideFragment(android.support.v4.app.Fragment fragment) {
    getSupportFragmentManager().beginTransaction().hide(fragment).commit();
}

private void showFragment(android.support.v4.app.Fragment fragment) {
    android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    if (!fragment.isAdded()) {
        transaction.add(R.id.fragment_container, fragment);
    }
    transaction.show(fragment).commitAllowingStateLoss();
}

// Native Version:
private void hideFragment(android.app.Fragment fragment) {
    getFragmentManager().beginTransaction().hide(fragment).commit();
}

private void showFragment(android.app.Fragment fragment) {
    android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
    if (!fragment.isAdded()) {
        transaction.add(R.id.fragment_container, fragment);
    }
    transaction.show(fragment).commitAllowingStateLoss();
}

To avoid confusion, I removed the import so classes require full names.

John Pang
  • 2,403
  • 25
  • 25