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?

biquillo
fonte
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

PJL
fonte
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);
Morten Holmgaard
fonte
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();
}
dbm
fonte
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);
Md Mohsin
fonte
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();
}
Belphegor
fonte
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)
georgehardcore
fonte
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.

Nicks
fonte
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(); }
trans
fonte
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();
    }
}
Arhat Baid
fonte
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);
    }
}
Chenxi
fonte
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();
            }
        }
    });
}
saulobrito
fonte
1

Está funcionando para mim, tente este:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }
Alok Singh
fonte
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.
Wajid Ali
fonte
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;
}
user3509903
fonte
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