Essa é a maneira correta de limpar a pilha traseira do fragmento ao deixar uma pilha profundamente aninhada?


130

Estou usando a biblioteca de compatibilidade do Android para implementar fragmentos e estendemos o exemplo de layout para que um fragmento contenha um botão que dispara outro fragmento.

No painel de seleção à esquerda, tenho 5 itens selecionáveis ​​- A B C D E.

Cada um carrega um fragmento (via FragmentTransaction:replace) no painel de detalhes -a b c d e

Agora estendi o fragmento epara conter um botão que carrega outro fragmento e1também no painel de detalhes. Eu fiz isso no emétodo onClick do fragmento da seguinte maneira:

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details_frag, newFrag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();

Se eu fizer as seguintes seleções:

E - e - e1 - D - E

Em seguida, o fragmento eestá no painel de detalhes. Isso está bem e o que eu quero. No entanto, se eu apertar o backbotão neste momento, não faz nada. Eu tenho que clicar duas vezes, porque e1ainda está na pilha. Além disso, depois de clicar ao redor, recebi uma exceção de ponteiro nulo no onCreateView:

Para 'resolver' esse problema, adicionei o seguinte sempre que A B C D Eé selecionado:

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

Imaginando se essa é a solução correta ou se eu deveria estar fazendo algo diferente.

Respostas:


252

Bem, existem algumas maneiras de fazer isso, dependendo do comportamento pretendido, mas esse link deve fornecer todas as melhores soluções e não surpreendentemente é de Dianne Hackborn

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

Essencialmente, você tem as seguintes opções

  • Use um nome para o seu estado inicial da pilha traseira e use FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • Use FragmentManager.getBackStackEntryCount()/ getBackStackEntryAt().getId() para recuperar o ID da primeira entrada na pilha traseira e FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) deve aparecer a pilha traseira inteira ... Acho que a documentação para isso está errada. (Na verdade, acho que não cobre o caso em que você entra POP_BACK_STACK_INCLUSIVE),

O que isto significa? FragmentManager.getBackStackEntryCount () / getBackStackEntryAt () getId ().
dannyroa

4
2 funcionou para mim. O que significa limpar toda a pilha: getSupportFragmentManager (). PopBackStack (getSupportFragmentManager (). GetBackStackEntryAt (0) .getId (), FragmentManager.POP_BACK_STACK_INCLUSIVE);
Nickl

@JorgeGarcia é possível, após o popbackstack, terminarmos nosso fragmento sem reiniciar o antigo.
duggu

Observe que também existe a versão popBackStackImmediate (), pois popBackStack () é assíncrono, o que significa que a limpeza não ocorre no momento exato em que você chama o método.
Genc

6
Reivindicações do grupo é banido como spam e não consigo acessar o link :( alguém tem o recurso em outro lugar?
EpicPandaForce

61

A outra solução limpa, se você não quiser exibir todas as entradas da pilha ...

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_container, fragmentInstance).addToBackStack(null).commit();

Isso limpará a pilha primeiro e, em seguida, carregará um novo fragmento; portanto, a qualquer momento, você terá apenas um fragmento na pilha


1
Isso é muito ruim: getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);antes de um replace (), porque estão carregando o chamado Fragmento onCreateView(), onActivityCreated()etc. Restaurar e Destroing um Fragmento instantaneamente é ruim. O fragmento pode registrar um receptor, por exemplo. Isso afeta o desempenho.
21819 VasileM #

@ VasileM, você poderia descrever em detalhes? Em que casos é ruim? É por causa do comportamento assíncrono de FragmentTransaction? Existe apenas um desempenho ruim da pilha de fragmentos incorreta?
CoolMind 16/12/19

27

Graças à resposta do Joachim , uso o código para limpar todas as entradas da pilha traseira finalmente.

// In your FragmentActivity use getSupprotFragmentManager() to get the FragmentManager.

// Clear all back stack.
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackCount; i++) {

    // Get the back stack fragment id.
    int backStackId = getSupportFragmentManager().getBackStackEntryAt(i).getId();

    getSupportFragmentManager().popBackStack(backStackId, 
        FragmentManager.POP_BACK_STACK_INCLUSIVE);

} /* end of for */

18
Por que usar um loop aqui? Para mim FragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) cancelou todas as entradas da pilha de volta ...
Marek

3
@Marek, porque às vezes nem todos os fragmentos devem ser removidos, um loop é adequado para isso.
CoolMind 08/12/16

1
@CoolMind, isso ainda não faz sentido para mim. popBackStack(backStackId, INCLUSIVE)exibirá todos os fragmentos (estados) de volta ao backStackId; assim, quando você exibir o menor número ique você irá exibir, todos os itens mais altos deverão aparecer ao mesmo tempo. Então, qual é o sentido de um loop?
LarsH 13/11/19

@ LarsH, você está certo. Consulte stackoverflow.com/a/59158254/2914140 . Para colocar outros fragmentos na tag necessária, devemos primeiro adicionar o fragmento com addToBackStack ( tag ).
CoolMind 16/12/19

7

Pesquisei bastante para limpar o Backstack e, finalmente, consulte o Transaction BackStack e seu gerenciamento . Aqui está a solução que funcionou melhor para mim.

 // CLEAR BACK STACK.
    private void clearBackStack() {
        final FragmentManager fragmentManager = getSupportFragmentManager();
        while (fragmentManager.getBackStackEntryCount() != 0) {
            fragmentManager.popBackStackImmediate();
        }
    }

O método acima faz um loop em todas as transações no backstack e as remove imediatamente uma de cada vez.

Nota: o código acima, em algum momento, não funciona e eu enfrento o ANR por causa desse código, portanto, não tente isso.

A atualização abaixo do método remove todos os fragmentos desse "nome" do backstack.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • nome Se não for nulo, este é o nome de um estado anterior anterior a ser procurado; se encontrado, todos os estados até esse estado serão exibidos. o
  • O sinalizador POP_BACK_STACK_INCLUSIVE pode ser usado para controlar se o próprio estado nomeado é exibido. Se nulo, apenas o estado superior será exibido.

Não vejo por que você os removeria um de cada vez. Existe uma razão pela qual você escolheu essa solução em vez das outras soluções? Existe uma razão para removê-los um de cada vez, em vez de todos de uma vez?
miva2

não existe nenhum método para remover o backstack de uma só vez, consulte developer.android.com/reference/android/app/…
Lokesh

3

Estou usando um código semelhante aos que usam o loop while, mas eu chamo a contagem de entradas em cada loop ... então suponho que seja um pouco mais lento

FragmentManager manager = getFragmentManager();
while (manager.getBackStackEntryCount() > 0){
        manager.popBackStackImmediate();
    }

0

Conforme escrito em Como destacar fragmento do backstack e por LarsH aqui, podemos vários fragmentos de cima para baixo para uma tag específica ( junto com o fragmento marcado ) usando este método:

fragmentManager?.popBackStack ("frag", FragmentManager.POP_BACK_STACK_INCLUSIVE);

Substitua "frag" pela tag do seu fragmento. Lembre-se de que primeiro devemos adicionar o fragmento ao backstack com:

fragmentTransaction.addToBackStack("frag")

Se adicionarmos fragmentos addToBackStack(null), não apareceremos os fragmentos dessa maneira.


-4
    // pop back stack all the way
    final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    int entryCount = fm.getBackStackEntryCount(); 
    while (entryCount-- > 0) {
        fm.popBackStack();
    }
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.