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

Posted

技术标签:

【中文标题】Android 同时使用 getFragmentManager 和 getSupportFragmentManager 会导致重叠【英文标题】:Android using both getFragmentManager and getSupportFragmentManager causes overlapping 【发布时间】:2015-03-25 15:55:26 【问题描述】:

我的活动中有这样的东西:

@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 示例使用需要旧 FragmentManager 的 support.v4.Fragment 的 ListView。那么如何将两个 FragmentManager 集成在一起呢?

【问题讨论】:

只需为您的所有Fragments 使用android.support.v4.Fragment 类,事情对您来说会容易得多。支持库中的几乎所有内容都将基于支持Fragments 但问题是我实现了 supportfragment 不支持的方法。 :/ 我希望仍然只保留和使用片段而不是支持片段。这可能吗? 如果您想使用支持库中的功能,请不要这样做。您在原生 Fragment 中实现了哪些支持 Fragment 无法实现的功能?在大多数情况下,迁移应该只是导入的变化。 【参考方案1】:

我在使用 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

您需要检查您要使用的片段类型(支持与否),并检查这些变量以查看最后一个片段是否属于不同类型。如果是这种情况,请清理其他片段管理器以“清除”屏幕,以免它们重叠。

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

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

希望对你有帮助:)

【讨论】:

但是通过这样做我假设您可以使用后退按钮在片段管理器上执行弹出堆栈? 如果您使用不同的片段管理器并使用后退按钮,您可以在当前的片段管理器上执行弹出堆栈,如果您的最后一个片段进入另一个片段管理器,您将不会简单地得到它,我会建议您自行处理onBackPressed 听起来有点骇人听闻。但我想它会起作用的。谢谢。 (:【参考方案2】:

这个答案的灵感来自 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;

【讨论】:

【参考方案3】:

我使用BottomNavigationView 作为标签栏并将片段切换为标签。除了一个片段之外的所有片段都是Support Fragments(最后一个片段是PreferenceFragment)。我使用的是“隐藏添加显示”而不是“删除替换”。因此,可以保留其他选项卡中的片段状态。

原功能切换:

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

所以,这个函数仍然做同样的事情,但通过检查目标类在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,因此类需要全名。

【讨论】:

以上是关于Android 同时使用 getFragmentManager 和 getSupportFragmentManager 会导致重叠的主要内容,如果未能解决你的问题,请参考以下文章

(android)十进制格式,使用逗号代替句号,同时使用“#.##”进行格式化

你想不想同时使用多个版本的Android studio

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

使用 OpenSL ES Android 同时播放多个音效

android中的NullPointerException,同时在menu.xml中使用actionLayout

同时使用前置和后置摄像头android