Bagaimana cara mendapatkan Fragmen untuk menghapus sendiri, yaitu setara dengan finish ()?

230

Saya mengonversi aplikasi untuk menggunakan fragmen menggunakan perpustakaan kompatibilitas. Sekarang saat ini saya memiliki sejumlah kegiatan (ABCD) yang berantai satu sama lain, D memiliki tombol 'OK' yang ketika panggilan selesai ditekan yang kemudian muncul onActivityResult()untuk menghancurkan C dan B.

Untuk versi fragmen Honycomb pra saya, setiap kegiatan secara efektif merupakan pembungkus pada fragmen Af Bf Cf Df. Semua aktivitas diluncurkan melalui startActivityForResult()dan onActivityResult()dalam setiap fragmen yang dapat dengan senang hati dipanggilgetActivity().finish()

Masalah yang saya alami adalah dalam versi Honeycomb saya, saya hanya memiliki satu aktivitas, A, dan fragmen Bf, Cf, Df yang dimuat menggunakan FragmentManager.

Apa yang saya tidak mengerti adalah apa yang harus dilakukan dalam Df ketika 'OK' ditekan untuk menghapus fragmen Df, Cf, dan Bf?

Saya mencoba memiliki fragmen muncul dari tumpukan tetapi ini menghasilkan pengecualian. onActivityResult()tidak berguna karena saya belum memuat fragmen menggunakan startActivityForResult().

Apakah saya memikirkan hal ini sepenuhnya salah? Haruskah saya menerapkan semacam pendengar yang berkomunikasi dengan fragmen induk atau aktivitas untuk melakukan pop menggunakan manajer transaksi?

PJL
sumber
7
bagaimana dengan ((YourActivity) getActivity ()). onBackPressed ();
Viswanath Lekshmanan
@ViswanathLekshmanan jawaban komentar Anda bermanfaat bagi saya .. 1 Suara positif dari saya
Abhishek Singh
@AbhishekSingh Bagus untuk mendengar :)
Viswanath Lekshmanan
@ViswanathLekshmanan :)
Abhishek Singh

Jawaban:

62

Apa yang saya tidak mengerti adalah apa yang harus dilakukan dalam Df ketika 'OK' ditekan untuk menghapus fragmen Df, Cf, dan Bf?

Langkah # 1: Minta beri tahu D "yo! Kami mendapat klik OK!" melalui memanggil suatu metode, baik pada aktivitas itu sendiri, atau pada instance antarmuka yang disediakan oleh aktivitas.

Langkah # 2: Minta D menghapus fragmen melalui FragmentManager.

Aktivitas hosting (D) adalah yang tahu apa fragmen lain dalam aktivitas tersebut (vs. berada di aktivitas lain). Oleh karena itu, peristiwa dalam fragmen yang mungkin mempengaruhi campuran fragmen harus disebarkan ke aktivitas, yang akan membuat orkestrasi bergerak sesuai.

CommonsWare
sumber
Tetapi dalam versi Honeycomb saya tidak ada D, itu sulit bagi saya. Hanya ada aktivitas A yang memuat fragmen Bf, yang memuat Cf, yang memuat Df menggunakan FragmentTransaction.
PJL
1
@PJL: Maaf, maksud saya A. Ini adalah salah satu alasan untuk menggunakan antarmuka pendengar, jadi beberapa aktivitas semua dapat menanggapi acara "kami mendapat klik OK" dari Df.
CommonsWare
1
Karena saya saat ini porting saya memanggil metode pendengar dari fragmen metode onActivityResult Df ke dalam aktivitas dimana saya kemudian memanggil popBackStack pada FragmentManager. Namun, ini menghasilkan pengecualian "IllegalStateException: Tidak dapat melakukan tindakan ini setelah diSaveInstanceState '. Ada gagasan tentang bagaimana saya bisa mengatasinya?
PJL
1
@DiegoPalomar: finish()sudah cukup.
CommonsWare
1
@ user3364963: Sudah lama sejak saya menyelidiki itu, tapi IIRC, itu hancur ketika muncul dari tumpukan belakang. Tambahkan onDestroy()metode ke fragmen Anda dan lihat apakah itu dipanggil.
CommonsWare
313

Meskipun mungkin bukan pendekatan terbaik yang setara terdekat saya bisa memikirkan yang berfungsi adalah ini dengan perpustakaan dukungan / kompatibilitas

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

atau

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

jika tidak.

Selain itu, Anda dapat menggunakan backstack dan pop itu. Namun perlu diingat bahwa fragmen mungkin tidak ada di backstack (tergantung pada fragmen transaksi yang sampai di sana ..) atau mungkin bukan yang terakhir yang masuk ke tumpukan sehingga memunculkan tumpukan bisa menghilangkan yang salah ...

Manfred Moser
sumber
11
Sementara pendekatan ini bekerja, jika Anda menggunakan addToBackStack (null) itu akan meninggalkan pengendali tombol kembali +1. Jadi, Anda harus menekannya dua kali.
user123321
34
"pop" fragmen dari FragmentManager.
user123321
2
Saya telah mencoba prosedur di atas tetapi memberikan kesalahan ini "java-lang-illegalstateexception-bisa-tidak-melakukan-tindakan-ini-setelah-onsavein". Jadi di mana tepatnya saya harus menghapus fragmen
KK_07k11A0585
6
Jawaban ini adalah praktik yang buruk dan tidak boleh memberikan suara. Fragmen tidak dimaksudkan untuk menjadi sadar diri seperti ini. Ini membunuh penggunaan kembali, yang merupakan titik fragmen! Fragmen harus memberi sinyal aktivitas untuk menghapusnya melalui sejumlah cara. Metode antarmuka panggilan balik adalah pilihan yang populer. developer.android.com/training/basics/fragments/…
colintheshots
2
@ManfredMoser Saya tidak setuju. Inilah inti pertanyaannya. Dia memiliki seluruh urutan fragmen untuk dihapus. Kode ini tidak memiliki cek nol atau memeriksa apakah kegiatan tersebut dilampirkan. Ini akan pecah dalam produksi karena tergantung pada banyak hal yang tidak diketahui oleh sebuah fragmen.
colintheshots
263

Anda dapat menggunakan pendekatan di bawah ini, itu berfungsi dengan baik:

getActivity().getSupportFragmentManager().popBackStack();
Eric Yuan
sumber
44
Jawaban ini seperti 10 kali lebih baik daripada yang diterima - langsung ke intinya.
nikib3ro
50
Ini juga 10 kali lebih buruk dalam hal desain daripada yang diterima. Sebuah fragmen seharusnya menjadi "pembantu" kecil untuk suatu kegiatan dan seharusnya tidak pernah mengontrol dirinya sendiri atau fragmen lainnya
Patrick
6
Solusinya tidak benar seperti yang ditunjukkan @avalancha. Lihatlah developer.android.com/guide/components/…
the_dark_destructor
2
Saya menggunakan metode ini padaActivityResult dan mendapatkan kesalahan "Tidak dapat melakukan tindakan ini setelah onSaveInstanceState". Bagaimana saya bisa mengatasinya?
Jayeshkumar Sojitra
1
popBackStack()adalah satu-satunya solusi yang berfungsi ketika Anda ingin mengatur judul bilah tindakan kembali ke keadaan sebelumnya setelah Anda menghapus fragmen. Kalau tidak, saya tidak perlu menggabungkan kedua solusi berperingkat tinggi dari stackoverflow.com/questions/13472258/… dan solusi ini di sini untuk selalu menetapkan judul bar tindakan yang tepat setelah berbagai kasus penggunaan. seperti menekan kembali, menghapus, menambahkan penggantian, dan sebagainya.
Bevor
36

Anda harus membiarkan Kegiatan berurusan dengan menambah dan menghapus Fragmen, seperti kata CommonsWare, menggunakan pendengar. Berikut ini sebuah contoh:

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());
            }
        });
    }
}
Blundell
sumber
5
Bunuh diri banyak gaya emo? Bagaimana dengan "Penutupan Sendiri" atau "Penutupan Otomatis" atau "SmartClose" (r)
DritanX
21
itu tidak menutup itu DYING SELAMANYA ;-(
Blundell
3
Ini adalah pendekatan yang jauh lebih bersih daripada jawaban lainnya. Aktivitas menciptakan dan menyajikan fragmen, dan harus mengontrol siklus hidupnya. Ketika sesuatu terjadi yang menunjukkan fragmen seharusnya tidak lagi terlihat, itu harus memberi tahu Aktivitas itu dan membiarkan aktivitas menghapusnya.
Christopher Pickslay
7
Secara teknis, jika kita seharusnya memiliki aktivitas membunuh fragmen, maka fragmen tidak bunuh diri. Aktivitas ini adalah pembunuhan.
Casey Murray
17

Dalam 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();
        }
    }
}

lalu panggil fragmen:

getActivity().onBackPressed();

atau seperti yang dinyatakan dalam jawaban lain, sebut ini di fragmen:

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
Kode terbalik
sumber
5

Jika Anda menggunakan Komponen Navigasi baru, sesederhana itu

findNavController().popBackStack()

Ini akan melakukan semua Transaksi Fragment di belakang untuk Anda.

Gastón Saillén
sumber
4

Lihat apakah kebutuhan Anda dipenuhi oleh DialogFragment. DialogFragment memiliki metode dismiss (). Jauh lebih bersih menurut saya.

Vasudev
sumber
3

Saya membuat metode sederhana untuk itu

popBackStack(getSupportFragmentManager());

Daripada menempatkannya di kelas ActivityUtils saya

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

Ini bekerja dengan baik, bersenang-senanglah!

Eliasz Kubala
sumber
2
Saya tidak mendapatkan tujuan metode Anda. PopBackStack asli tampaknya sepenuhnya memadai.
Luar biasa
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();

Ini adalah bagaimana saya menyembunyikan fragmen di event klik 1

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

Kemudian Perlihatkan kembali ke acara 2

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

Jika Anda perlu mem-popback dari fragmen keempat dalam sejarah backstack ke yang pertama, gunakan tag !!!

Saat Anda menambahkan fragmen pertama Anda harus menggunakan sesuatu seperti ini:

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

atau

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

Dan ketika Anda ingin menunjukkan Fragmen B, C dan D Anda menggunakan ini:

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

dan surat-surat lainnya ....

Untuk kembali ke FragmentA, panggil saja popBackStack(0, "A"), ya, gunakan bendera yang Anda tentukan saat Anda menambahkannya, dan perhatikan bahwa itu haruslah bendera yang sama dalam perintah addToBackStack(), bukan yang digunakan dalam perintah, ganti atau tambahkan.

Sama-sama ;)

Diego Ramírez Vásquez
sumber
Saya telah menguji 'popBackStack (0, "A")' dan aplikasi saya kembali ke fragmen A, tetapi saya hanya menginginkan fragmen itu akan dihapus dari Back Stack ... Bagaimana saya dapat menghapus fragmen dari Stack tanpa muncul di layar ??
KryNaC
1

Untuk Menutup fragmen sementara di dalam fragmen yang sama

getActivity().onBackPressed();
Dino Sunny
sumber
-9

Kenapa tidak adil:

getActivity (). finish ();

Akan
sumber
4
Ini akan menyelesaikan seluruh aktivitas tidak hanya fragmen.
Murtadha S.