Limpar a pilha traseira usando fragmentos


244

Portei meu aplicativo Android para o favo de mel e fiz um grande refator para usar fragmentos. Na minha versão anterior, quando eu pressionava o botão Início, fazia um ACTIVITY_CLEAR_TOPpara redefinir a pilha traseira.

Agora, meu aplicativo é apenas uma única atividade com vários fragmentos; portanto, quando pressiono o botão Início, substituo um dos fragmentos dentro dele. Como posso limpar minha pilha traseira sem precisar usar startActivitya ACTIVITY_CLEAR_TOPbandeira?


Evite usar pilhas de trás! isso realmente não ajuda com a eficiência geral! use plain replace () ou, melhor ainda, remova / adicione toda vez que quiser navegar! Verifique minha postagem em stackoverflow.com/questions/5802141/…
stack_ved

Respostas:


430

Eu postei algo parecido aqui

Da resposta de Joachim, de Dianne Hackborn:

http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42

Acabei usando:

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {    
    fm.popBackStack();
}

Mas poderia igualmente ter usado algo como:

((AppCompatActivity)getContext()).getSupportFragmentManager().popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

O que exibirá todos os estados até o nomeado. Você pode substituir o fragmento pelo que deseja


8
Bem, é equivalente a pressionar o botão voltar uma ou mais vezes, por isso altera o fragmento que está visível no momento. (Pelo menos quando eu tentei)
Peter Ajtai

7
Estou tendo o mesmo problema que o Peter. Eu gostaria de limpar todos os fragmentos, em vez de fazer um ciclo através deles, o que tem muitas implicações. Por exemplo, você atingirá eventos do ciclo de vida dos quais não precisa, retirando todos os fragmentos da pilha sequencialmente.
Brian Griffey

233
Para ir ao topo, basta usar: fragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Warpzit

53
Para o que vale a pena, usando fragmentManager. popBackStackImmediate (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); trabalhou ainda melhor para mim, uma vez que impediu as animações fragmento de executar
roarster

17
Isto não funcionar corretamente - ele irá acionar uma chamada para onStart de cada fragmento entre
James

165

Para responder ao comentário de @ Warpzit e facilitar a localização de outras pessoas.

Usar:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

14
Acredito que a remoção de todos os fragmentos do backstack dessa maneira tenha sido quebrada na biblioteca v7-appCompat mais recente ao usar AppCompatActivity. Depois de atualizar meu aplicativo para a última biblioteca v7-appCompat (21.0.0) e estender a nova AppCompatActivity, popping fragmentos da maneira acima está deixando alguns fragmentos no registro de backstack do FragmentManager. Eu aconselho a não usar isso.
dell116

Pode ser usado popBackStackImmediate.
Kannan_SJD

38

Com todo o respeito a todas as partes envolvidas; Estou muito surpreso ao ver quantos de vocês conseguiram limpar todo o fragmento da pilha traseira com um simples

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

De acordo com a documentação do Android (referente ao nameargumento - o "nulo" nas propostas de trabalho reivindicadas).

Se nulo, apenas o estado superior será exibido

Agora, percebo que não tenho conhecimento de suas implementações específicas (como quantas entradas você tem na pilha traseira no momento especificado), mas eu apostaria todo meu dinheiro na resposta aceita ao esperar uma resposta bem definida. comportamento em uma ampla variedade de dispositivos e fornecedores:

(para referência, algo junto com isso)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}

4
para mim, não foi porque cada pop leva você internamente ao onCreateView de cada fragmento. Onde eu receberia um NPE em algum recurso. Mas usando fm.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); simplesmente matou todo o backstack.
sud007

1
Alguma idéia de como ignorar chamadas onCreateView ao aparecer usando loop?
Ayush Goyal

Limpar o fragmento mais alto (nulo) limpará todos os fragmentos que vierem depois dele na pilha de trás.
2778-445-4c77-b1eb-4df3e5

18

Funciona para mim e de maneira fácil sem usar loop:

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

17

A resposta aceita não foi suficiente para mim. Eu tive que usar:

FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
    fm.popBackStackImmediate();
}

2
Isso foi apontado em uma resposta diferente, mas apenas para garantir que seja observado: se você colocar a pilha inteira em um loop como esse, você acionará os métodos do ciclo de vida de cada fragmento entre o início e o final da pilha. . Há uma boa chance de que essa implementação tenha consequências indesejadas, na maioria dos casos de uso. Também vale ressaltar que popBackStackImmediate()realiza a transação de forma síncrona, o que é geralmente desaconselhável.
Damien Diehl

16

Backstack claro sem loops

String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Onde name é o parâmetro addToBackStack ()

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)

mesmo se u substituir pilha .fragment vai estar vivo, mas não visível
asthme

8

Eu só queria adicionar: -

Sair do backstack usando as seguintes

fragmentManager.popBackStack ()

trata-se de remover os fragmentos da transação, de maneira alguma ele removerá o fragmento da tela. Então, idealmente, pode não ser visível para você, mas pode haver dois ou três fragmentos empilhados um sobre o outro e, ao pressionar a tecla Voltar, a interface do usuário pode parecer desordenada, empilhada.

Apenas tomando um exemplo simples: -

Suponha que você tenha um fragmentoA que carrega o Fragmnet B usando fragmentmanager.replace () e, em seguida, adicionamosToToBackStack, para salvar esta transação. Então o fluxo é: -

PASSO 1 -> Fragmento A-> Fragmento B (passamos para o Fragmento B, mas o Fragmento A está em segundo plano, não visível).

Agora, você trabalha no fragmento B e pressiona o botão Salvar - que após salvar deve voltar ao fragmento A.

PASSO 2-> Ao salvar o FragmentB, voltamos ao FragmentA.

PASSO 3 -> Um erro tão comum seria ... no fragmento B, faremos o fragmento Manager.replace () fragmentB pelo fragmentoA.

Mas o que realmente está acontecendo, estamos carregando o Fragmento A novamente, substituindo o FragmentoB. Portanto, agora existem dois FragmentosA (um do PASSO-1 e um deste PASSO-3).

Duas instâncias de FragmentsA são empilhadas umas sobre as outras, que podem não estar visíveis, mas estão lá.

Portanto, mesmo se limparmos o backstack pelos métodos acima, a transação será limpa, mas não os fragmentos reais. Então, idealmente, nesse caso particular, ao pressionar o botão Salvar, você simplesmente precisa voltar ao fragmento A, executando simplesmente fm.popBackStack () ou fm.popBackImmediate () .

Portanto, corrija o Passo 3 -> fm.popBackStack () para o fragmento A, que já está na memória.


3

Lendo a documentação e estudando qual é o ID do fragmento, ele parece ser simplesmente o índice da pilha, então isso funciona:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Zero ( 0) é a parte inferior da pilha; portanto, aparecer nela limpa a pilha.

CAVEAT: Embora o acima funcione no meu programa, hesito um pouco porque a documentação do FragmentManager nunca afirma que o id é o índice da pilha. Faz sentido que seria, e todos os meus logs de depuração revelam que é, mas talvez em alguma circunstância especial não seria? Alguém pode confirmar isso de uma maneira ou de outra? Se for, o acima é a melhor solução. Caso contrário, esta é a alternativa:

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }

1
Que tal usar em fragmentManager..getBackStackEntryAt(0).getId()vez de 0? Isso deve funcionar mesmo se os IDs de entrada do backstack forem diferentes em algum momento do índice da pilha.
ChristophK

3

Basta usar esse método e passar a tag Context & Fragment até a qual precisamos remover os fragmentos de recuo.

Uso

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

2

Oi ~ Encontrei uma solução muito melhor em: 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);
    }
}

2
Por favor, expanda sua resposta sobre por que essa solução é melhor.
Simon.SA

Ele usa o mecanismo que o sdk fornece a si mesmo e não causa nenhum problema de npe.
Chenxi

1

Eu consegui trabalhar desta maneira:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}

1

Está funcionando para mim, tente este:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }

0
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

A chamada para esse método seria muito interessante.

  1. Não é necessário loop.
  2. Se você estiver usando animação em fragmentos, ele não mostrará muitas animações. Mas usar loop vontade.

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

Obrigado por este trecho de código, que pode fornecer ajuda imediata e limitada. Uma explicação adequada melhoraria bastante seu valor a longo prazo, mostrando por que essa é uma boa solução para o problema e a tornaria mais útil para futuros leitores com outras perguntas semelhantes. Por favor edite sua resposta para adicionar alguma explicação, incluindo as suposições que você fez.
Abdelilah El Aissaoui
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.