Como descartar corretamente um DialogFragment?

121

Os documentos dizem isso para o dismiss()método da Dialogclasse:

Dispensar esta caixa de diálogo, removendo-a da tela. Este método pode ser invocado com segurança a partir de qualquer thread. Observe que você não deve substituir esse método para fazer a limpeza quando a caixa de diálogo for fechada, em vez disso, implemente-o em onStop().

No meu código, tudo o que faço é ligar getDialog().dismiss()para descartá-lo. Mas não estou fazendo mais nada, nem mesmo usando onStop(). Portanto, estou perguntando exatamente como descartar corretamente um DialogFragmentpara evitar qualquer vazamento de memória, etc.

Andy
fonte

Respostas:

197

tl; dr: A maneira correta de fechar a DialogFragmenté usar dismiss() diretamente no DialogFragment .


Detalhes : a documentação dos estados de DialogFragment

O controle da caixa de diálogo (decidir quando mostrar, ocultar ou dispensar) deve ser feito por meio da API aqui, não com chamadas diretas na caixa de diálogo.

Portanto, você não deve usar getDialog().dismiss(), pois isso invocaria dismiss() na caixa de diálogo . Em vez disso, você deve usar o dismiss()método do próprio DialogFragment:

public void dispens ()

Dispensar o fragmento e sua caixa de diálogo. Se o fragmento foi adicionado à pilha de retorno, todo o estado da pilha de retorno até e incluindo esta entrada será exibido. Caso contrário, uma nova transação será confirmada para remover o fragmento.

Como você pode ver, isso cuida não apenas de fechar o diálogo, mas também de lidar com as transações de fragmento envolvidas no processo.

Você só precisa usar onStopse tiver criado explicitamente quaisquer recursos que requeiram limpeza manual (arquivos de fechamento, cursores de fechamento, etc.). Mesmo assim, eu substituiria onStopo DialogFragment em vez onStopdo Dialog subjacente.

Heinzi
fonte
1
@ScootrNova: Não deveria, você provavelmente tem um bug em outro lugar. Como você está criando o fragmento?
Heinzi
protected void showDialogFragment(final DialogFragment fragment) {final FragmentTransaction fTransaction = getSupportFragmentManager().beginTransaction(); fTransaction.addToBackStack(null); fragment.show(fTransaction, "dialog");} Desculpe pelo forro desagradável! Mas sim, você pode estar certo, então, por enquanto, escrevi outra maneira de fechar meus DialogFragments. A maneira que eu estava dispensando-os usando o método dispensar () foi apenas localizando o fragmento por tag e, em seguida, executando despedir () nele se não fosse nulo. Ah, sim, estou newpegando o fragmento antes de passá-lo para esse método.
Charles Madere
2
@ScootrNova: Hmm, não vejo nada de errado nisso - por outro lado, nunca usei a biblioteca de compatibilidade, então não posso ter certeza disso. Talvez faça sentido criar um exemplo mínimo e independente e começar uma nova pergunta sobre isso.
Heinzi
@CharlesMadere naquela época, você encontrou uma solução?
JCarlosR
Desculpe @JCarlos, isso foi há anos, não tenho certeza.
Charles Madere
76

Acho que a melhor maneira de fechar um DialogFragmenté esta:

Fragment prev = getSupportFragmentManager().findFragmentByTag("fragment_dialog");
if (prev != null) {
    DialogFragment df = (DialogFragment) prev;
    df.dismiss();
}

Dessa forma, você não precisa manter uma referência ao DialogFragmente pode fechá-lo de qualquer lugar.

Terel
fonte
7

Por que você não tenta usar apenas este código:

dismiss();

Se você quiser dispensar o Fragmento de Diálogo por conta própria. Você pode simplesmente colocar este código dentro do fragmento da caixa de diálogo onde deseja descartar a caixa de diálogo.

Por exemplo:

button.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
       dismiss();
   }
});

Isso fechará o fragmento de diálogo recente que é mostrado na tela.

Espero que ajude para você.

Shiva Tiwari
fonte
não trabalhando o tempo todo
Mahmoud Heretani
5

Eu dei um voto positivo à resposta de Terel. Eu só queria postar isso para qualquer usuário do Kotlin:

supportFragmentManager.findFragmentByTag(TAG_DIALOG)?.let {
    (it as DialogFragment).dismiss()
}
JustinMorris
fonte
Código simples funciona muito, obrigado pelo amigo de atualização !!
Ayush Katuwal
4

Versão Kotlin da resposta Terel

(fragmentManager.findFragmentByTag(TAG) as? DialogFragment)?.dismiss()
Phil
fonte
1

Você deve demitir-se Dialogem onPause()modo substituí-lo.

Além disso, antes de dispensar, você pode verificar nullse o snippet a seguir está exibindo:

@Override
protected void onPause() {
    super.onPause();
    if (dialog != null && dialog.isShowing()) {
        dialog.dismiss();
    }
}
Venky
fonte
ele já escreveu que está fazendo despedir () e é sobre DialogFragment.
Paresh Mayani
Eu acho que isso funciona para Dialog e DialogFragments @PareshMayani
Venky
2
Eu acredito que @PareshMayani está correto, Venky. O tutorial DialogFragmentdo google não mostra o onPause()método que está sendo usado. Mas acho que vejo o que você está fazendo. Qual é o ponto, se o usuário não estiver ligando onPause(). É quando o sistema sabe que o fragmento está sendo retirado. E quando, digamos, um usuário cancelar. Qual é a melhor maneira de fechá-lo nesse caso?
Andy
1

Há referências aos documentos oficiais ( Referência DialogFragment ) em outras respostas, mas nenhuma menção ao exemplo dado ali:

void showDialog() {
    mStackLevel++;

    // DialogFragment.show() will take care of adding the fragment
    // in a transaction.  We also want to remove any currently showing
    // dialog, so make our own transaction and take care of that here.
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    Fragment prev = getFragmentManager().findFragmentByTag("dialog");
    if (prev != null) {
        ft.remove(prev);
    }
    ft.addToBackStack(null);

    // Create and show the dialog.
    DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel);
    newFragment.show(ft, "dialog");
}

Isso remove qualquer diálogo mostrado atualmente, cria um novo DialogFragment com um argumento e o mostra como um novo estado na pilha posterior. Quando a transação é exibida, o DialogFragment atual e seu diálogo serão destruídos e o anterior (se houver) será mostrado novamente. Observe que, neste caso, o DialogFragment se encarregará de abrir a transação da caixa de diálogo que será descartada separadamente dela.

Para minhas necessidades, mudei para:

FragmentManager manager = getSupportFragmentManager();
Fragment prev = manager.findFragmentByTag(TAG);
if (prev != null) {
    manager.beginTransaction().remove(prev).commit();
}

MyDialogFragment fragment = new MyDialogFragment();
fragment.show(manager, TAG);
Maksim Ivanov
fonte
1

Somando-se as outras respostas, ao ter uma DialogFragmentchamada em tela cheia, dismiss()o DialogFragment não será retirado do backstack do fragmento. Uma solução alternativa é chamar onBackPressed()a atividade pai.

Algo assim:

CustomDialogFragment.kt

closeButton.onClick {
    requireActivity().onBackPressed()
}
mikehc
fonte
Salve o dia, muito obrigado
Mahmoud Heretani
0

Basta chamar ignorar () a partir do fragmento que deseja dispensar.

imageView3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            dismiss();
        }
    });
VIVEK CHOUDHARY
fonte
0

Descobri que quando meu fragmento foi definido no gráfico de navegação com uma <fragment>tag (para um dialogfragment de tela inteira), o dialogfragment não descartava com o dismiss()comando. Em vez disso, tive que abrir a pilha de volta:

findNavController(getActivity(), R.id.nav_host_fragment).popBackStack();

No entanto, se o mesmo fragmento de diálogo foi definido no gráfico de navegação com uma <dialog>tag, dismiss()funciona bem.

Jon
fonte
0
CustomFragment dialog = (CustomDataFragment) getSupportFragmentManager().findFragmentByTag("Fragment_TAG");
if (dialog != null) {
  dialog.dismiss();
}
Victor Odiah
fonte