Como fazer com que um fragmento se remova, ou seja, seu equivalente a finish ()?


230

Estou convertendo um aplicativo para usar fragmentos usando a biblioteca de compatibilidade. Agora, atualmente, tenho várias atividades (ABCD) que se encadearam, D tem um botão 'OK' que, quando pressionado, termina e depois borbulha onActivityResult()para destruir adicionalmente C e B.

Para minha versão anterior do fragmento Honycomb, cada atividade é efetivamente um invólucro nos fragmentos Af Bf Cf Df. Todas as atividades são iniciadas via startActivityForResult()e onActivityResult()dentro de cada um dos fragmentos podem chamargetActivity().finish()

O problema que estou tendo, porém, está na minha versão do Honeycomb; só tenho uma atividade, A, e os fragmentos Bf, Cf, Df são carregados usando o FragmentManager.

O que não entendo é o que fazer em Df quando 'OK' é pressionado para remover os fragmentos Df, Cf e Bf?

Tentei fazer com que o fragmento aparecesse da pilha, mas isso resultou em uma exceção. onActivityResult()é inútil porque não carreguei o fragmento usando startActivityForResult().

Estou pensando nisso completamente da maneira errada? Devo estar implementando algum tipo de ouvinte que se comunica com o fragmento ou atividade pai para fazer o pop usando o gerenciador de transações?


7
que tal ((YourActivity) getActivity ()). onBackPressed ();
Viswanath Lekshmanan

@ViswanathLekshmanan a resposta do seu comentário é útil para mim .. 1 voto positivo de mim
Abhishek Singh

@AbhishekSingh bom ouvir :)
Viswanath Lekshmanan

@ViswanathLekshmanan :)
Abhishek Singh

Respostas:


62

O que não entendo é o que fazer em Df quando 'OK' é pressionado para remover os fragmentos Df, Cf e Bf?

Etapa 1: Faça com que Df diga D "yo! Temos o clique OK!" através da chamada de um método, na própria atividade ou em uma instância de interface fornecida pela atividade.

Etapa 2: Faça com que D remova os fragmentos via FragmentManager.

A atividade de hospedagem (D) é aquela que sabe quais outros fragmentos estão na atividade (versus estar em outras atividades). Portanto, os eventos no fragmento que podem afetar a mistura de fragmentos devem ser propagados para a atividade, o que fará os movimentos apropriados da orquestração.


Mas na minha versão do Honeycomb não há D, essa é a minha dificuldade. Existe simplesmente uma atividade A que carrega o fragmento Bf, que carrega Cf, que carrega Df usando FragmentTransaction.
PJL

1
@PJL: Desculpe, eu quis dizer A. Esta é uma razão para usar uma interface de ouvinte, para que várias atividades possam responder ao evento "obtivemos o clique OK" da Df.
CommonsWare

1
Como estou portando, chamei um método listener do método onActivityResult dos fragmentos Df para a atividade em que chamei popBackStack no FragmentManager. No entanto, isso resulta em uma exceção "IllegalStateException: Não é possível executar essa ação após onSaveInstanceState' Alguma idéia de como posso superar isso.?
PJL

1
@ DiegoPalomar: finish()deve ser suficiente.
CommonsWare

1
@ user3364963: Já faz algum tempo que eu investiguei isso, mas o IIRC é destruído quando é retirado da pilha de trás. Adicione um onDestroy()método ao seu fragmento e veja se ele é chamado.
CommonsWare

313

Embora possa não ser a melhor abordagem, o equivalente mais próximo que consigo pensar é que funciona com a biblioteca de suporte / compatibilidade

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

ou

getActivity().getFragmentManager().beginTransaction().remove(this).commit();

de outra forma.

Além disso, você pode usar o backstack e abri-lo. No entanto, lembre-se de que o fragmento pode não estar no backstack (dependendo da transação do fragmento que chegou lá ..) ou pode não ser o último que entrou na pilha, portanto, estourar a pilha pode remover o errado ...


11
Enquanto essa abordagem funciona, se você estiver usando addToBackStack (null), ela deixará o manipulador de botão voltar +1. Então você terá que pressionar duas vezes.
user123321

34
"pop" o fragmento do FragmentManager.
user123321

2
Eu tentei o procedimento acima, mas está dando esse erro "java-lang-ilegalstateexception-can-not-not-execute-this-action-after-onsaveinstance". Então, onde exatamente eu tenho que remover o fragmento
KK_07k11A0585

6
Essa resposta é uma prática ruim e não deve ser levantada. Fragmentos não devem ser autoconscientes assim. Mata a reutilização, que é o ponto dos fragmentos! O fragmento deve sinalizar a atividade para removê-lo através de qualquer número de meios. O método da interface de retorno de chamada é uma escolha popular. developer.android.com/training/basics/fragments/…
colintheshots 13/04/2015

2
@ManfredMoser Não concordo. Este é o objetivo da questão. Ele tem uma sequência inteira de fragmentos para remover. Este código não possui verificações nulas ou verifica se a atividade está anexada. A produção será interrompida porque depende de muitas coisas que um fragmento não sabe.
Colintheshots 13/04/2015

263

Você pode usar a abordagem abaixo, ela funciona bem:

getActivity().getSupportFragmentManager().popBackStack();

44
Essa resposta é 10 vezes melhor que a aceita - direto ao ponto.
Nikib3ro

50
Também é 10 vezes pior com relação ao design do que o aceito. Um fragmento é suposto ser uma pequena "helper" para uma atividade e nunca deve bei no controle sobre si mesmo ou outros fragmentos
Patrick

6
A solução não está correta, como @avalancha apontou. Dê uma olhada em developer.android.com/guide/components/…
the_dark_destructor 4/13/13

2
Estou usando esse método onActivityResult e obtendo o erro "Não é possível executar esta ação após onSaveInstanceState". Como posso resolver isso?
Jayeshkumar Sojitra

1
popBackStack()é a única solução que funciona quando você deseja definir o título da barra de ação de volta ao estado anterior depois de excluir o fragmento. Caso contrário, eu não precisaria combinar as duas soluções de alta classificação de stackoverflow.com/questions/13472258/… e esta solução aqui para sempre definir o título da barra de ação adequada após vários casos de uso. como pressionar novamente, excluir, adicionar substituições etc.
Bevor

36

Você deve deixar a atividade lidar com a adição e remoção de fragmentos, como o CommonsWare diz, usar um ouvinte. Aqui está um exemplo:

public class MyActivity extends FragmentActivity implements SuicidalFragmentListener {

    // onCreate etc

    @Override
    public void onFragmentSuicide(String tag) {
        // Check tag if you do this with more than one fragmen, then:
        getSupportFragmentManager().popBackStack();
    }
}

public interface SuicidalFragmentListener {
    void onFragmentSuicide(String tag);
}

public class MyFragment extends Fragment {

    // onCreateView etc

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
           suicideListener = (SuicidalFragmentListener) activity;
        } catch (ClassCastException e) {
           throw new RuntimeException(getActivity().getClass().getSimpleName() + " must implement the suicide listener to use this fragment", e);
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Attach the close listener to whatever action on the fragment you want
        addSuicideTouchListener();
    }

    private void addSuicideTouchListener() {
        getView().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              suicideListener.onFragmentSuicide(getTag());
            }
        });
    }
}

5
Suicídio muito estilo emo? Como sobre "fecho automático" ou "AutoClose" ou "SmartClose" (r)
DritanX

21
não está fechando, está morrendo para sempre ;-(
Blundell

3
Essa é uma abordagem muito mais limpa do que as outras respostas. A atividade cria e apresenta o fragmento e deve controlar seu ciclo de vida. Quando algo que indica que o fragmento não deve mais estar em exibição, ele deve informar a atividade e deixar que a atividade o remova.
Christopher Pickslay

7
Tecnicamente, se devemos fazer com que a atividade mate o fragmento, o fragmento não é suicida. A atividade é homicida.
Casey Murray

17

Em Activity / AppCompatActivity:

@Override
public void onBackPressed() {
    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        // if you want to handle DrawerLayout
        mDrawerLayout.closeDrawer(GravityCompat.START);
    } else {
        if (getFragmentManager().getBackStackEntryCount() == 0) {
            super.onBackPressed();
        } else {
            getFragmentManager().popBackStack();
        }
    }
}

e depois chame o fragmento:

getActivity().onBackPressed();

ou como indicado em outras respostas, chame isso no fragmento:

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

5

Se você estiver usando o novo componente de navegação, é simples como

findNavController().popBackStack()

Ele fará toda a FragmentTransaction atrás de você.


4

Veja se suas necessidades são atendidas por um DialogFragment. DialogFragment possui um método de descarte (). Muito mais limpo na minha opinião.


3

Eu crio um método simples para isso

popBackStack(getSupportFragmentManager());

Em seguida, coloque-o na minha classe ActivityUtils

public static void popBackStack(FragmentManager manager){
        FragmentManager.BackStackEntry first = manager.getBackStackEntryAt(0);
        manager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

É um ótimo trabalho, divirta-se!


2
Eu não entendo o propósito do seu método. O popBackStack original parece completamente adequado.
A incrível Jan

1

OnCreate:

//Add comment fragment
            container = FindViewById<FrameLayout>(Resource.Id.frmAttachPicture);
            mPictureFragment = new fmtAttachPicture();

            var trans = SupportFragmentManager.BeginTransaction();
            trans.Add(container.Id, mPictureFragment, "fmtPicture");
            trans.Show(mPictureFragment); trans.Commit();

É assim que eu oculto o fragmento no evento click 1

//Close fragment
    var trans = SupportFragmentManager.BeginTransaction();
    trans.Hide(mPictureFragment);
    trans.AddToBackStack(null);
    trans.Commit();

Em seguida, mostra de volta int evento 2

var trans = SupportFragmentManager.BeginTransaction();
            trans.Show(mPictureFragment); trans.Commit();

1

Se você precisar voltar do quarto fragmento do histórico do backstack para o primeiro, use tags !!!

Quando você adiciona o primeiro fragmento, deve usar algo como isto:

getFragmentManager.beginTransaction.addToBackStack("A").add(R.id.container, FragmentA).commit() 

ou

getFragmentManager.beginTransaction.addToBackStack("A").replace(R.id.container, FragmentA).commit()

E quando você deseja mostrar os fragmentos B, C e D, você usa isso:

getFragmentManager.beginTransaction.addToBackStack("B").replace(R.id.container, FragmentB, "B").commit()

e outras letras ....

Para retornar a FragmentA, basta chamar popBackStack(0, "A"), sim, use o sinalizador que você especificou ao adicioná-lo e observe que ele deve ser o mesmo sinalizador no comandoaddToBackStack() , e não o usado no comando substituir ou adicionar.

De nada ;)


Eu testei 'popBackStack (0, "A")' e meu aplicativo volta ao fragmento A, mas quero que apenas esse fragmento seja removido do Back Stack ... Como remover o fragmento do Stack sem aparecer na tela?
KryNaC

1

Para fechar um fragmento enquanto estiver dentro do mesmo fragmento

getActivity().onBackPressed();

-9

Por que não apenas:

getActivity (). finish ();


4
Isso finalizará toda a atividade, não apenas o fragmento.
Murtadha S.
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.