Bagaimana cara menutup DialogFragment dengan benar?

121

Dokumen mengatakan ini untuk dismiss()metode dari Dialogkelas:

Singkirkan dialog ini, hapus dari layar. Metode ini dapat dipanggil dengan aman dari utas mana pun. Perhatikan bahwa Anda tidak boleh mengganti metode ini untuk melakukan pembersihan saat dialog ditutup, sebagai gantinya terapkan di onStop().

Dalam kode saya, yang saya lakukan hanyalah menelepon getDialog().dismiss()untuk menutupnya. Tetapi saya tidak melakukan hal lain atau bahkan menggunakan onStop(). Jadi saya bertanya dengan tepat bagaimana cara menutup dengan benar DialogFragmentuntuk menghindari kebocoran memori, dll ..

Andy
sumber

Jawaban:

197

tl; dr: Cara yang benar untuk menutup a DialogFragmentadalah dengan menggunakan dismiss() langsung pada DialogFragment .


Detail : Dokumentasi status DialogFragment

Kontrol dialog (memutuskan kapan akan menampilkan, menyembunyikan, menutupnya) harus dilakukan melalui API di sini, bukan dengan panggilan langsung pada dialog.

Jadi, Anda tidak boleh menggunakan getDialog().dismiss(), karena itu akan memanggil dismiss() dialog . Sebagai gantinya, Anda harus menggunakan dismiss()metode DialogFragment itu sendiri:

public void bubar ()

Singkirkan fragmen dan dialognya. Jika fragmen ditambahkan ke back-stack, semua status back-stack hingga dan termasuk entri ini akan dimunculkan. Jika tidak, transaksi baru akan dilakukan untuk menghapus fragmen.

Seperti yang Anda lihat, ini tidak hanya menangani penutupan dialog tetapi juga menangani transaksi fragmen yang terlibat dalam proses tersebut.

Anda hanya perlu menggunakan onStopjika Anda secara eksplisit membuat sumber daya apa pun yang memerlukan pembersihan manual (menutup file, menutup kursor, dll.). Bahkan kemudian, saya akan mengganti onStopDialogFragment daripada onStopDialog yang mendasarinya.

Heinzi
sumber
1
@ScootrNova: Seharusnya tidak, Anda mungkin memiliki bug di tempat lain. Bagaimana Anda membuat fragmen?
Heinzi
protected void showDialogFragment(final DialogFragment fragment) {final FragmentTransaction fTransaction = getSupportFragmentManager().beginTransaction(); fTransaction.addToBackStack(null); fragment.show(fTransaction, "dialog");} Maaf untuk satu kapal yang buruk! Tapi ya Anda mungkin benar, jadi untuk saat ini saya telah menulis cara lain untuk menutup DialogFragments saya. Cara saya mengabaikan mereka menggunakan metode reject () hanya menemukan fragmen dengan tag dan kemudian menjalankan reject () di atasnya jika bukan null. Oh dan ya, saya sedang newmemasukkan fragmen tepat sebelum meneruskannya ke metode itu.
Charles Madere
2
@ScootrNova: Hmm, tidak ada yang salah dengan itu - di sisi lain, saya tidak pernah menggunakan pustaka kompatibilitas, jadi saya tidak yakin tentang itu. Mungkin masuk akal untuk membuat contoh mandiri yang minimal dan memulai pertanyaan baru tentang itu.
Heinzi
@CharlesMadere pada masa itu, apakah Anda menemukan solusi?
JCarlosR
Maaf @JCarlos, ini bertahun-tahun yang lalu, saya tidak yakin.
Charles Madere
76

Saya pikir cara yang lebih baik untuk menutup a DialogFragmentadalah ini:

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

Dengan cara ini Anda tidak perlu memiliki referensi ke DialogFragmentdan dapat menutupnya dari mana saja.

Terel
sumber
7

Mengapa Anda tidak mencoba hanya menggunakan kode ini:

dismiss();

Jika Anda ingin menutup Fragmen Dialog dengan sendirinya. Anda cukup meletakkan kode ini di dalam fragmen dialog tempat Anda ingin menutup Dialog.

Sebagai contoh:

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

Ini akan menutup Fragmen Dialog terbaru yang ditampilkan di layar.

Semoga bisa membantu Anda.

Shiva Tiwari
sumber
tidak bekerja sepanjang waktu
Mahmoud Heretani
5

Saya memberikan suara positif untuk jawaban Terel. Saya hanya ingin memposting ini untuk semua pengguna Kotlin:

supportFragmentManager.findFragmentByTag(TAG_DIALOG)?.let {
    (it as DialogFragment).dismiss()
}
JustinMorris
sumber
Kode sederhana bekerja keras, Terima kasih atas pembaruannya sobat !!
Ayush Katuwal
4

Jawaban Terel Versi Kotlin

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

Anda harus memecat Anda Dialogdi onPause()sehingga menimpa itu.

Juga sebelum menutup Anda dapat memeriksa nulldan menampilkan seperti di bawah ini cuplikan:

@Override
protected void onPause() {
    super.onPause();
    if (dialog != null && dialog.isShowing()) {
        dialog.dismiss();
    }
}
Venky
sumber
dia telah menulis bahwa dia melakukan pemberhentian () dan tentang DialogFragment.
Paresh Mayani
Saya pikir ini berfungsi untuk Dialog dan DialogFragments @PareshMayani
Venky
2
Saya yakin @PareshMayani adalah Venky yang benar. Tutorial DialogFragmentoleh google tidak menunjukkan onPause()metode yang digunakan sama sekali. Tapi saya rasa saya melihat apa yang Anda lakukan. Apa gunanya jika pengguna tidak menelepon onPause(). Saat itulah sistem mengetahui bahwa fragmen sedang dipanggil. Bagaimana dengan kapan, misalnya pengguna membatalkan. Apa cara yang lebih baik untuk menutupnya dalam kasus itu?
Andy
1

Ada referensi ke dokumen resmi ( DialogFragment Reference ) di jawaban lain, tetapi tidak disebutkan contoh yang diberikan di sana:

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

Ini akan menghapus dialog yang ditampilkan saat ini, membuat DialogFragment baru dengan argumen, dan menampilkannya sebagai status baru di back-stack. Saat transaksi dimunculkan, DialogFragment saat ini dan Dialognya akan dihancurkan, dan yang sebelumnya (jika ada) ditampilkan kembali. Perhatikan bahwa dalam hal ini, DialogFragment akan menangani pemunculan transaksi Dialog secara terpisah darinya.

Untuk kebutuhan saya, saya mengubahnya menjadi:

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
sumber
1

Menambahkan ke jawaban lain, saat memiliki DialogFragmentpanggilan layar penuh dismiss()tidak akan memunculkan DialogFragment dari backstack fragmen. Solusinya adalah dengan memanggil onBackPressed()aktivitas induk.

Sesuatu seperti ini:

CustomDialogFragment.kt

closeButton.onClick {
    requireActivity().onBackPressed()
}
mikehc
sumber
Selamatkan hari, terima kasih banyak
Mahmoud Heretani
0

Panggil saja pemberhentian () dari fragmen yang ingin Anda tutup.

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

Saya menemukan bahwa ketika fragmen saya didefinisikan dalam grafik navigasi dengan <fragment>tag (untuk dialogfragmen layar penuh), dialogfragmen tidak akan ditutup dengan dismiss()perintah. Sebagai gantinya, saya harus mengeluarkan tumpukan belakang:

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

Namun, jika dialogfragmen yang sama ditentukan dalam grafik navigasi dengan <dialog>tag, dismiss()berfungsi dengan baik.

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