Android: возврат к предыдущему фрагменту при обратном нажатии

Я реализовал панель навигации, которая является подклассом Activity. У меня в заявке много фрагментов. Мой вопрос здесь

Представьте, что есть 3 фрагмента:

Фрагмент_1: Фрагмент_2: Фрагмент_3

Когда я запускаю свое приложение, загружается Fragment_1. Когда я нажимаю на некоторые компоненты на Fragment_1, я перехожу к Fragment_2 и т. Д.

Так это как

Фрагмент_1> Фрагмент_2> Фрагмент_3

Когда я нажимаю клавишу возврата из фрагмента_2, я возвращаюсь к фрагменту_1, но когда я нажимаю клавишу возврата из фрагмента_3, я возвращаюсь к фрагменту_1 (вместо фрагмента_2)

Я хочу что-то подобное в моем приложении при нажатии клавиши "Назад"

Фрагмент_1 ‹Фрагмент_2‹ Фрагмент_3

Я использовал Fragment, FragmentManager, FragmentTransaction следующим образом:

MyFragment fragment = new MyFragment();
FragmentManager fragmentManager = getFragmentManager();

fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).addToBackStack(null)commit();

и я попытался переопределить onBackPressed () в своей MainActivity:

@Override
public void onBackPressed() {


        getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        int count = getFragmentManager().getBackStackEntryCount();
        if (count == 0)
               super.onBackPressed();
    }

person Harsh    schedule 17.08.2014    source источник


Ответы (5)


Обновите свой Activity#onBackPressed() метод, чтобы:

@Override
public void onBackPressed() {
    if (getFragmentManager().getBackStackEntryCount() > 0) {
        getFragmentManager().popBackStack();
    } else {
        super.onBackPressed();
    }
}

Причина, по которой ваша реализация не работает, заключается в том, что метод FragmentManager#popBackStack() является асинхронным и не выполняется сразу после его вызова.

Из документации:

Эта функция является асинхронной - она ​​ставит запрос на извлечение, но действие не будет выполнено, пока приложение не вернется в свой цикл обработки событий.

Ссылка: http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack(java.lang.String,%20int)

person Leandro    schedule 17.08.2014
comment
Ваш код работает отчасти. Проблема в том, что :: Предположим, я перемещаюсь следующим образом ›› Fragment_1 ›Fragment_2› Fragment_3, а затем из панели навигации я снова выбираю Fragment_1 и перемещаюсь так же, как показано ниже, а затем, нажимая клавишу возврата, я нахожу следующую последовательность Fragment_1 ‹Fragment_2‹ Fragment_3 ‹Fragment_1 ‹Фрагмент_2‹ Фрагмент_3 - person Harsh; 17.08.2014
comment
Вы получаете эту последовательность, потому что каждая FragmentManager операция, которую вы выполняете, добавляется в задний стек через FragmentTransaction#addToBackStack(). Я еще раз прочитал ваш вопрос и до сих пор не знаю, чего вы ожидаете в этом случае. Просьба уточнить. - person Leandro; 17.08.2014
comment
на самом деле ваш код решил мою проблему. Но как изменить следующую последовательность: Fragment_1 ‹Fragment_2‹ Fragment_3 ‹Fragment_1‹ Fragment_2 ‹Fragment_3 на Fragment_1‹ Fragment_2 ‹Fragment_3 ..... Независимо от повторного действия пользователя как Fragment_1› Fragment_2 ›Fragment_3. Если вы все еще не поняли мою точку зрения, то другой термин для обозначения моей проблемы - удаление избыточности одних и тех же фрагментов. - person Harsh; 17.08.2014
comment
Я предполагаю, что вы планируете сделать так, чтобы избежать дублирования записей в стеке FragmentManager и Back, верно? Если это так, вы можете проверить, находится ли Fragment уже в стеке, установив TAG при фиксации его, и они будут искать его (с FragmentManager#findFragmentByTag(String TAG) и не вызывать addToBackStack(), если он не возвращает нулевое значение. Также отметьте мой ответ как ответ на вопрос, решил ли он вашу проблему. - person Leandro; 17.08.2014
comment
Вы можете проиллюстрировать это коротким примером? (код для findFragmentByTag (...)) - person Harsh; 18.08.2014

Вы должны реализовать свою собственную реализацию backstack, как описано здесь

Отдельный задний стек для каждой вкладки в Android с использованием фрагментов

Вы можете вызывать popFragments () всякий раз, когда вы нажимаете кнопку «Назад» во фрагменте, и вызывать pushFragments () всякий раз, когда вы переходите от одного фрагмента к другому.

Суммируя,

public void onBackPressed()
{
    FragmentManager fm = getActivity().getSupportFragmentManager();
    fm.popBackStack();
}
person Sam    schedule 17.08.2014

Трика находится в FragmentManager#executePendingTransactions();.

Это то, что я использую и для вложенных фрагментов ...:

/**
 * if there is a fragment and the back stack of this fragment is not empty,
 * then emulate 'onBackPressed' behaviour, because in default, it is not working.
 *
 * @param fm the fragment manager to which we will try to dispatch the back pressed event.
 * @return {@code true} if the onBackPressed event was consumed by a child fragment, otherwise
 */
public static boolean dispatchOnBackPressedToFragments(FragmentManager fm) {

    List<Fragment> fragments = fm.getFragments();
    boolean result;
    if (fragments != null && !fragments.isEmpty()) {
        for (Fragment frag : fragments) {
            if (frag != null && frag.isAdded() && frag.getChildFragmentManager() != null) {
                // go to the next level of child fragments.
                result = dispatchOnBackPressedToFragments(frag.getChildFragmentManager());
                if (result) return true;
            }
        }
    }

    // if the back stack is not empty then we pop the last transaction.
    if (fm.getBackStackEntryCount() > 0) {
        fm.popBackStack();
        fm.executePendingTransactions();
        return true;
    }

    return false;
}

и в моем onBackPressed:

                if (!FragmentUtils.dispatchOnBackPressedToFragments(fm)) {
                    // if no child fragment consumed the onBackPressed event,
                    // we execute the default behaviour.
                    super.onBackPressed();
                }
person ahmed_khan_89    schedule 03.05.2016
comment
Очень полезный ответ. - person Umang Mathur; 06.02.2017

Используйте этот код при смене вкладки в своем основном действии, чтобы очистить стек.

int count = getFragmentManager().getBackStackEntryCount();
        if(count>0){
            for (int i = 0; i <count; i++) {
                getFragmentManager().popBackStack();
            }
        }

Затем, нажав кнопку "Назад" основного действия, сделайте следующее.

 int count = getFragmentManager().getBackStackEntryCount();

     if (count == 0) {
         super.onbackpressed();
        }
else {
        getFragmentManager().popBackStack();
    }
 }
person Nanda    schedule 25.09.2015

Вот рабочий и проверенный мной код, это поможет вам

 private static final int TIME_INTERVAL = 2000;
private long mBackPressed;
 private void applyExit() {
    if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) {
        finish();
    } else {
         Toast.makeText(this,"Press Again to exit",Toast.LENGTH_LONG).show();
    }
    mBackPressed = System.currentTimeMillis();
}

@Override
public void onBackPressed() {
    fm = getSupportFragmentManager();
    if (drawer.isDrawerOpen(GravityCompat.START)) {
        drawer.closeDrawer(GravityCompat.START);
    }
    if (fm.getFragments().size() <= 1) {
        applyExit();
    } else {
        for (Fragment frag : fm.getFragments()) {
            if (frag == null) {
                applyExit();
                return;
            }
            if (frag.isVisible()) {
                FragmentManager childFm = frag.getChildFragmentManager();
                if (childFm.getFragments() == null) {
                    super.onBackPressed();
                    return;
                }
                if (childFm.getBackStackEntryCount() > 0) {
                    childFm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                    return;
                } else {
                    fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                    return;
                }
            }
        }
    }
}
person Ness Tyagi    schedule 08.11.2016