Очистить задний стек, используя фрагменты
Я портировал свое Android-приложение на соты и сделал большой рефакторинг, чтобы использовать фрагменты. В моей предыдущей версии, когда я нажимал кнопку "Домой", я делал ACTIVITY_CLEAR_TOP
чтобы сбросить задний стек.
Теперь мое приложение представляет собой одно действие с несколькими фрагментами, поэтому, когда я нажимаю кнопку "Домой", я просто заменяю один из фрагментов внутри него. Как я могу очистить свой стек без использования startActivity
с ACTIVITY_CLEAR_TOP
флаг?
16 ответов
Я выложил что-то подобное здесь
Из ответа Иоахима, от Дайан Хакборн:
http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42
В итоге я просто использовал:
FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
fm.popBackStack();
}
Но в равной степени мог бы использовать что-то вроде:
FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)
Который выскочит все состояния до названного. Затем вы можете просто заменить фрагмент на то, что вы хотите
Чтобы ответить на комментарий @Warpzit и сделать его проще для других.
Использование:
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
При всем уважении ко всем вовлеченным сторонам; Я очень удивлен, увидев, сколько из вас может очистить весь стек обратно с помощью простого
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Согласно документации Android (относительно name
аргумент - "ноль" в заявленных рабочих предложениях).
Если ноль, только верхнее состояние выталкивается
Теперь я понимаю, что мне не хватает знаний о ваших конкретных реализациях (например, сколько записей у вас в заднем стеке на данный момент времени), но я бы поставил все свои деньги на принятый ответ, ожидая четко определенного Поведение более широкого круга устройств и поставщиков:
(для справки, что-то вместе с этим)
FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
fm.popBackStack();
}
Очистить бэкстек без петель
String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Где name это параметр addToBackStack()
getSupportFragmentManager().beginTransaction().
.replace(R.id.container, fragments.get(titleCode))
.addToBackStack(name)
У меня работает и простой способ без использования цикла:
FragmentManager fragmentManager = getSupportFragmentManager();
//this will clear the back stack and displays no animation on the screen
fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Принятого ответа мне не хватило. Я должен был использовать:
FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
fm.popBackStackImmediate();
}
Привет ~ Я нашел решение, которое гораздо лучше, с: https://gist.github.com/ikew0ng/8297033
/**
* Remove all entries from the backStack of this fragmentManager.
*
* @param fragmentManager the fragmentManager to clear.
*/
private void clearBackStack(FragmentManager fragmentManager) {
if (fragmentManager.getBackStackEntryCount() > 0) {
FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
Я просто хотел добавить:-
Выскочить из backstack, используя следующие
fragmentManager.popBackStack()
это просто удаление фрагментов из транзакции, и ни в коем случае не удаление фрагмента с экрана. Поэтому в идеале он может быть невидим для вас, но может быть два или три фрагмента, накладываемые друг на друга, и при нажатии клавиши "назад" пользовательский интерфейс может выглядеть загроможденным, сложенным.
Просто приведу простой пример:
Предположим, у вас есть фрагмент A, который загружает Fragmnet B с помощью fragmanager.replace (), а затем мы добавляем addToBackStack, чтобы сохранить эту транзакцию. Итак, поток:
ШАГ 1 -> FragmentA->FragmentB (мы переместились во FragmentB, но фрагмент A находится в фоновом режиме, а не видим).
Теперь вы делаете некоторую работу во фрагменте B и нажимаете кнопку "Сохранить", которая после сохранения должна вернуться к фрагменту A.
ШАГ 2-> При сохранении FragmentB мы возвращаемся к FragmentA.
ШАГ 3 -> Так что распространенная ошибка будет... во фрагменте B мы сделаем фрагмент Manager.replace() фрагмент B с фрагментом A.
Но что на самом деле происходит, мы снова загружаем фрагмент А, заменяя фрагмент Б. Итак, теперь есть два фрагмента A (один из STEP-1 и один из этого STEP-3).
Два экземпляра фрагментов A накладываются друг на друга, которые могут быть не видны, но они есть.
Таким образом, даже если мы очищаем backstack вышеуказанными методами, транзакция очищается, но не фактические фрагменты. Так что в идеале в таком конкретном случае при нажатии кнопки сохранения вам просто нужно вернуться к фрагменту A, просто выполнив fm.popBackStack() или fm.popBackImmediate ().
Поэтому исправьте Step3-> fm.popBackStack() и вернитесь к фрагменту A, который уже находится в памяти.
Для тех, кто живет здесь, котлинов:
repeat(supportFragmentManager.backStackEntryCount) {
supportFragmentManager.popBackStack()
}
Читая документацию и изучая, что такое идентификатор фрагмента, он выглядит просто как индекс стека, так что это работает:
fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Нуль (0
) - это нижняя часть стека, поэтому всплывающее окно до него включительно очищает стек.
ПРЕДУПРЕЖДЕНИЕ. Хотя вышеперечисленное работает в моей программе, я немного сомневаюсь, потому что документация FragmentManager фактически никогда не утверждает, что id является индексом стека. Это имеет смысл, и все мои журналы отладки показывают, что это так, но, может быть, в некоторых особых обстоятельствах это не так? Кто-нибудь может подтвердить это так или иначе? Если это так, то вышеупомянутое является лучшим решением. Если нет, то это альтернатива:
while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }
Это работает для меня, попробуйте это:
public void clearFragmentBackStack() {
FragmentManager fm = getSupportFragmentManager();
for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
fm.popBackStack();
}
}
Просто используйте этот метод и передайте тег Context & Fragment, в который нам нужно удалить фрагменты обратного удара.
использование
clearFragmentByTag(context, FragmentName.class.getName());
public static void clearFragmentByTag(Context context, String tag) {
try {
FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();
for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
String backEntry = fm.getBackStackEntryAt(i).getName();
if (backEntry.equals(tag)) {
break;
} else {
fm.popBackStack();
}
}
} catch (Exception e) {
System.out.print("!====Popbackstack error : " + e);
e.printStackTrace();
}
}
Я получил это работает так:
public void showHome() {
getHandler().post(new Runnable() {
@Override
public void run() {
final FragmentManager fm = getSupportFragmentManager();
while (fm.getBackStackEntryCount() > 0) {
fm.popBackStackImmediate();
}
}
});
}
Расширение Котлина
fun AppCompatActivity.clearAllFragments() {
supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
}
private void clearBackStack(){
SupportFragmentManaer fm = getSupportFragmentManager();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
Вызов этого метода будет очень аккуратным.
- Петля не требуется.
- Если вы используете анимацию во фрагментах, она не будет отображать слишком много анимаций. Но с помощью цикла будет.
private boolean removeFragFromBackStack() {
try {
FragmentManager manager = getSupportFragmentManager();
List<Fragment> fragsList = manager.getFragments();
if (fragsList.size() == 0) {
return true;
}
manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}