Android using both getFragmentManager and getSupportFragmentManager causes overlapping

戏子无情 提交于 2020-01-21 10:14:07

问题


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?


回答1:


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 :)




回答2:


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;
}



回答3:


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.



来源:https://stackoverflow.com/questions/28163631/android-using-both-getfragmentmanager-and-getsupportfragmentmanager-causes-overl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!