popBackStackImmediate не показывает фрагмент, когда текущая транзакция фрагмента не добавляется в backstack

Popbackstack работает нормально, когда все фрагменты в последовательности добавлены в backstack, но не работает, когда одна из транзакций не добавлена ​​в backstack.

Вот моя навигация:

1. Замените фрагмент, чтобы загрузить домашний фрагмент. Эта транзакция не добавлена ​​в стек.

  1. Замените фрагмент, чтобы загрузить фрагмент входа в систему. Эта транзакция добавляется в бэкстэк.

    3. Замените фрагмент, чтобы загрузить фрагмент входа в систему. Эта транзакция не добавляется в бэкстэк.

    Теперь, когда я нажимаю кнопку «Назад», ничего не происходит. Тогда как в идеале он должен переходить к домашнему фрагменту из фрагмента авторизации. Вот мой метод onbackpressed в основном действии:

    @Override
    public void onBackPressed() {
        if(getSupportFragmentManager().getBackStackEntryCount()>0)
        {
            FragmentManager.BackStackEntry backStackEntry = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1);
            String str = backStackEntry.getName();
            FragmentManager fm=getSupportFragmentManager();
            //getSupportFragmentManager().popBackStackImmediate();
            fm.popBackStack(str, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        }
        else {
            super.onBackPressed();
        }
    
    
    }
    

comment
Думаю, работает. Просто у вас отображаются оба фрагмента (ваш LoggedInFragment И ваш HomeFragment). Поскольку LoggedInFragment отображался после HomeFragment, HomeFragment не отображается как скрытый LoggedInFragment. Вы не можете ожидать, что LoggedInFragment исчезнет, ​​когда вы нажмете назад, поскольку транзакция не находится в заднем стеке.   -  person Eselfar    schedule 24.07.2017
comment
Итак, чтобы решить вашу проблему, одним из решений может быть проверка, является ли текущий фрагмент LoggedInFragment. Если это так, вы удаляете фрагмент из контейнера, а затем вставляете задний стек, чтобы вернуться домой.   -  person Eselfar    schedule 24.07.2017
comment
вау, ты абсолютно прав, спасибо большое.   -  person vipul bansal    schedule 24.07.2017
comment
но, пожалуйста, вместо комментария напишите его в ответ, чтобы мы оба могли набрать несколько очков.   -  person vipul bansal    schedule 24.07.2017
comment
Мое решение, приведенное выше, немного запутано. Еще один должен заключаться в том, чтобы добавить транзакцию в bs, затем, когда пользователь нажимает назад, вы проверяете, является ли это LoggedInFragment, и вы вставляете bs до homeFragment   -  person Eselfar    schedule 24.07.2017
comment
Я добавлю ответ   -  person Eselfar    schedule 24.07.2017
comment
Вы тоже можете написать решение в коде?   -  person vipul bansal    schedule 24.07.2017
comment
Я обновил свой ответ примером кода. Я не тестировал, но должен работать   -  person Eselfar    schedule 24.07.2017


Ответы (2)


popBackstack "выталкивать" только то, что находится в задней стопке. Поскольку вы не добавляли транзакцию при замене LoginFragment на LoggedInFragment, когда вы нажимаете назад:

  • LoggedInFragment остается,
  • появляется LogInFragment
  • отображается HomeFragment

Но поскольку LoggedInFragment был добавлен после HomeFragment, HomeFragment отображается под ним. Таким образом, вы не можете увидеть это как скрытое LoggedInFragment.

Одно из решений - добавить транзакцию в задний стек при замене LogInFragment на LoggedInFragment. Затем в onBackPressed вы проверяете, является ли текущий фрагмент LoggedInFragment. Если это так, вы вставляете задний стек в HomeFragment (не включительно). Таким образом, появятся и LoggedInFragment, и LogInFragment.

ИЗМЕНИТЬ

@Override
public void onBackPressed() {
    FragmentManager manager = getSupportFragmentManager();
    Fragment fragment = manager.findFragmentById(R.id.my_fragment_container);
    // If there is something in the back stack AND the current fragment is the LoggedInFragment
    if (manager.getBackStackEntryCount() > 0
            && fragment instanceof LoggedInFragment) {            
        manager.popBackStack(HomeFragment.class.getSimpleName(), 0);
    } else {
        super.onBackPressed();
    }
}

Чтобы получить HomeFragment по имени, вам нужно пометить свою транзакцию, когда вы заменяете текущий фрагмент HomeFragment. Обычно я помечаю все транзакции простым именем класса фрагмента, чтобы я мог повторить попытку любого фрагмента:

transaction.replace(R.id.my_fragment_container, fragment, fragment.getClass().getSimpleName());

person Eselfar    schedule 24.07.2017

Объяснение проблемы Эселфаром верно, но предоставленный им код не был достаточно универсальным для меня.

Я (надеюсь) решил эту проблему в общем случае с помощью следующего кода:

@Override
public void onBackPressed() {
    Fragment currentFragment = getCurrentFragment();

    if (mFragmentManager.getBackStackEntryCount() > 0) {

        // In a normal world, just popping back stack would be sufficient, but since android
        // is not normal, a call to popBackStack can leave the popped fragment on screen.
        // Therefore, we start with manual removal of the current fragment.
        removeCurrentFragment();

        mFragmentManager.popBackStack();
    } else {
        super.onBackPressed();
    }
}

private Fragment getCurrentFragment() {
    return mFragmentManager.findFragmentById(getContentFrameId());
}

private void removeCurrentFragment() {
    FragmentTransaction ft = mFragmentManager.beginTransaction();
    ft.remove(getCurrentFragment());
    ft.commit();

    // not sure it is needed; will keep it as a reminder to myself if there will be problems
    // mFragmentManager.executePendingTransactions();
}
person Vasiliy    schedule 25.11.2017
comment
Когда вам звонят navigateUp()? Чтобы использовать onBackPressed с фрагментами, ваша Activity должна реализовать FragmentActivity. - person Eselfar; 26.11.2017
comment
navigateUp() вызывается, когда пользователь нажимает кнопку вверх на панели инструментов. - person Vasiliy; 26.11.2017
comment
Вы по-прежнему можете вызывать onBackPressed() вручную в своем методе. Если вы не хотите, например OP, определенного поведения, вам даже не нужно переопределять onBackPressed саму себя. Просто убедитесь, что ваша активность расширяет FragmentActivity, если вы используете фрагменты - person Eselfar; 27.11.2017
comment
Навигация вверх и назад - это не одно и то же. Например. когда пользователь входит в приложение через уведомление на экране, не являющемся приземлением, навигация вверх должна удерживать его / ее в приложении, а навигация назад должна возвращать его туда, откуда он / она пришел. - person Vasiliy; 27.11.2017
comment
Да, ты прав. Итак, как ваш вопрос связан с вопросом OP, если у вас, похоже, другая проблема? Обычно OP пытается управлять кнопкой «Назад», когда ваш чехол поднят. - person Eselfar; 27.11.2017
comment
Ах, теперь я понимаю, что вы имеете в виду. Да, я, вероятно, ответил немного на другой вопрос, чем то, что задал OP. Я удалил код из ответа, чтобы он соответствовал функциональности назад. Что ты думаешь об этом сейчас? - person Vasiliy; 27.11.2017
comment
Что именно вы пытаетесь сделать? Я не понимаю, почему вы удаляете фрагмент, а затем вызываете popBackStack - person Eselfar; 27.11.2017
comment
Если отображаемый в данный момент фрагмент был добавлен в транзакцию, которая не была добавлена ​​в backstack, то простое извлечение backstack сохранит текущий отображаемый фрагмент на экране. Этот код решает эту проблему, всегда удаляя показанный в данный момент фрагмент в транзакции, которая не добавляется в backstack. Это как бы заставляет onBackPressed() работать так, как я ожидал - независимо от того, была ли последняя транзакция добавлена ​​в backstack или нет, текущий показанный фрагмент удаляется при нажатии на кнопку назад. - person Vasiliy; 27.11.2017
comment
Вообще-то, нет. Допустим, у вас есть фрагмент A, вы заменяете его фрагментом B и добавляете транзакцию в задний стек, затем вы заменяете его фрагментом C и не добавляете транзакцию в задний стек. Теперь, если вы нажмете назад, вы ожидаете, что окажетесь на фрагменте B, но вы находитесь на фрагменте A. В другом случае у вас есть фрагмент A, и вы замените его фрагментом B без добавления транзакции в задний стек, количество записей в обратном стеке будет не больше 0, поэтому будет вызван onBackPressed - person Eselfar; 27.11.2017
comment
Я понимаю, что вы пытаетесь сделать, но сначала это очень опасно, и в любом случае вам нужно реорганизовать свой код. - person Eselfar; 27.11.2017
comment
@Eselfar, я подумал о том, что вы говорите, и думаю, что у нас разные ожидания от поведения. Когда я нахожусь во фрагменте B и заменяю его фрагментом C без добавления в backstack, я ожидаю, что фрагмент B не будет доступен во время обратной навигации. Это больше соответствует распределению обязанностей - фрагмент B контролирует, доступен ли он сам по себе во время обратной навигации, вместо того, чтобы контролировать доступность фрагмента C. - person Vasiliy; 19.12.2017
comment
Это зависит от того, какие именно ваши фрагменты, но пользователь не знает и не заботится о backstack. Так что, отступая, он потенциально мог ожидать чего-то другого, чем вы, разработчик. - person Eselfar; 20.12.2017