Android, использующий как getFragmentManager, так и getSupportFragmentManager, вызывает перекрытие

У меня есть что-то вроде этого в моей деятельности:

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

Программа автоматически загружает case1, но когда выбран case2, getSupportFragmentManager загружает фрагмент поверх case1. Я предполагаю, что есть некоторые проблемы с использованием как supportFragmentManager, так и FragmentManager. Кажется, у них есть собственный стек. Проблема в том, что я не могу использовать только один из них, потому что пример Android SwipeToRefresh использует ListView, для которого требуется support.v4.Fragment, для которого нужен старый FragmentManager. Так как же можно интегрировать оба FragmentManager вместе?


person holyxiaoxin    schedule 27.01.2015    source источник
comment
Просто используйте класс android.support.v4.Fragment для всех ваших Fragments, и вам будет намного проще. Почти все в библиотеках поддержки будет основано на поддержке Fragments.   -  person Kevin Coppock    schedule 27.01.2015
comment
Но проблема в том, что я реализовал методы, которые не поддерживает supportfragment. :/ Я хочу сохранить и использовать только фрагмент вместо фрагмента поддержки. Это возможно?   -  person holyxiaoxin    schedule 27.01.2015
comment
Нет, если вы хотите использовать функции из библиотеки поддержки. Что вы реализовали в нативных фрагментах, чего нельзя сделать с помощью вспомогательных фрагментов? По большей части миграция должна быть просто изменением импорта.   -  person Kevin Coppock    schedule 27.01.2015


Ответы (3)


Я сделал что-то подобное при использовании PreferenceFragment (не поддерживается версией библиотеки поддержки). Чтобы добиться этого, я сохранил в своей деятельности пару логических значений (isLastFragmentSupportType и lastFragmentShowed), а также строку (lastFragmentTag).

В начале ваша активность будет иметь оба значения false. И когда вы добавляете новый фрагмент, вы используете эти 2 логических значения, чтобы узнать, нужно ли вам очищать другие 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, чтобы сохранить эти значения на случай, если они вам понадобятся.

Надеюсь, поможет :)

person zozelfelfo    schedule 27.01.2015
comment
Но, делая это, я предполагаю, что вы можете использовать кнопку «Назад», чтобы выполнить popstack в диспетчере фрагментов? - person holyxiaoxin; 27.01.2015
comment
Если вы используете разные менеджеры фрагментов и используете кнопку «Назад», вы МОЖЕТЕ выполнить popstack в вашем текущем диспетчере фрагментов, если ваш последний фрагмент был в другом диспетчере фрагментов, вы просто не получите его, я бы рекомендовал вам обрабатывать onBackPressed самостоятельно - person zozelfelfo; 27.01.2015
comment
Звучит немного по-хакерски. Но я думаю, это сработает. Спасибо. (: - person holyxiaoxin; 27.01.2015

Этот ответ вдохновлен ответом 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;
}
person penduDev    schedule 03.02.2016

Я использую 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 Fragment и Native 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, поэтому для классов требуются полные имена.

person John Pang    schedule 20.12.2017