Android 同时使用 getFragmentManager 和 getSupportFragmentManager 导致重叠

Android using both getFragmentManager and getSupportFragmentManager causes overlapping

我的 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.我想同时使用 supportFragmentManager 和 FragmentManager 有一些问题。他们似乎有自己的堆栈。问题是我不能只使用其中一个,因为 SwipeToRefresh Android 示例使用需要支持的 ListView。v4.Fragment 需要旧的 FragmentManager。那么如何将两个 FragmentManagers 集成在一起呢?

我在使用 PreferenceFragment(支持库版本不支持)时完成了类似的事情。为了实现这一点,我在 Activity 中保留了一对布尔值(isLastFragmentSupportTypelastFragmentShowed)以及一个字符串(lastFragmentTag)。

一开始你的 Activity 会让它们都为 false。当你添加一个新的 Fragment 时,你使用这两个布尔值来知道你是否需要清理另一个 FragmentManager 。我将以您的代码为例:

@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

您需要检查您要使用的片段类型(支持与否),并检查这些变量以查看最后一个片段是否属于不同类型。如果是这种情况,请将另一个 fragmentmanager 清理到 "clear" 屏幕,这样它们就不会重叠。

还可以使用 TAGS 来识别和检索您当前的片段,这样您的代码就不需要 Fragment 变量。

最后使用 onSavedInstanceState 以保留这些值以备不时之需。

希望对您有所帮助:)

这个答案的灵感来自于 zozelfelfo 的答案。 使用这两种方法替换片段而不是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;
}

我正在使用 BottomNavigationView 作为选项卡栏并将片段切换为选项卡。除一个片段外,所有片段均为 Support Fragments(最后一个片段为 PreferenceFragment)。我使用 "hide-add-show" 而不是 "remove-replace"。因此,可以保留其他选项卡中片段的状态。

要切换的原函数:

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

我既不使用标记也不使用布尔值,只是想保留对最后一个片段对象的引用。因此,切换时,只需使用任何片段的实例调用 switchFragment()

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

因此,此函数仍然执行相同的操作,但通过检查目标 class 在 Support FragmentNative Fragment 之间切换。辅助函数:

// 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();
}

为了避免混淆,我删除了 import,因此 classes 需要全名。