Saya memiliki masalah dalam membuat fragmen saya berkomunikasi satu sama lain melalui Activity
, yang menggunakan FragmentPagerAdapter
, sebagai kelas pembantu yang mengimplementasikan pengelolaan tab dan semua detail menghubungkan ViewPager
dengan yang terkait TabHost
. Saya telah menerapkan FragmentPagerAdapter
sama seperti yang disediakan oleh proyek sampel Android Support4Demos .
Pertanyaan utamanya adalah bagaimana saya bisa mendapatkan fragmen tertentu dari FragmentManager
saat saya tidak memiliki Id atau Tag? FragmentPagerAdapter
membuat fragmen dan otomatis menghasilkan Id dan Tag.
android
android-fragments
fragmentpageradapter
Ismar Slomic
sumber
sumber
Jawaban:
Ringkasan masalah
Catatan: Dalam jawaban ini saya akan merujuk
FragmentPagerAdapter
dan kode sumbernya. Tetapi solusi umum juga harus diterapkanFragmentStatePagerAdapter
.Jika Anda membaca ini, Anda mungkin sudah tahu bahwa
FragmentPagerAdapter
/FragmentStatePagerAdapter
dimaksudkan untuk dibuatFragments
untuk AndaViewPager
, tetapi setelah rekreasi Aktivitas (baik dari rotasi perangkat atau sistem yang mematikan Aplikasi Anda untuk mendapatkan kembali memori), iniFragments
tidak akan dibuat lagi, tetapi contoh diambil dariFragmentManager
. Sekarang katakanActivity
kebutuhan Anda untuk mendapatkan referensi tentang iniFragments
untuk mengerjakannya. Anda tidak memilikiid
atautag
untuk ini dibuatFragments
karenaFragmentPagerAdapter
menyetelnya secara internal . Jadi masalahnya adalah bagaimana mendapatkan referensi kepada mereka tanpa informasi itu ...Masalah dengan solusi saat ini: mengandalkan kode internal
Banyak solusi yang saya telah melihat hal ini dan yang sejenis pertanyaan mengandalkan mendapatkan referensi ke yang ada
Fragment
dengan memanggilFragmentManager.findFragmentByTag()
dan meniru tag dibuat secara internal:"android:switcher:" + viewId + ":" + id
. Masalahnya adalah Anda mengandalkan kode sumber internal, yang seperti yang kita semua tahu tidak dijamin akan tetap sama selamanya. Para insinyur Android di Google dapat dengan mudah memutuskan untuk mengubahtag
struktur yang akan merusak kode Anda sehingga Anda tidak dapat menemukan referensi ke yang sudah adaFragments
.Solusi alternatif tanpa mengandalkan internal
tag
Berikut adalah contoh sederhana tentang cara mendapatkan referensi ke yang
Fragments
dikembalikan olehFragmentPagerAdapter
yang tidak bergantung padatags
kumpulan internal diFragments
. Kuncinya adalah menggantiinstantiateItem()
dan menyimpan referensi di sana, bukan digetItem()
.atau jika Anda lebih memilih untuk bekerja dengan
tags
daripada variabel anggota kelas / referensi keFragments
Anda juga dapat mengambiltags
set denganFragmentPagerAdapter
dengan cara yang sama: CATATAN: ini tidak berlakuFragmentStatePagerAdapter
karena tidak diaturtags
saat membuat itsFragments
.Perhatikan bahwa metode ini TIDAK bergantung pada peniruan
tag
set internal olehFragmentPagerAdapter
dan sebagai gantinya menggunakan API yang tepat untuk mengambilnya. Dengan cara ini meskipuntag
perubahan di versi mendatangSupportLibrary
Anda akan tetap aman.Jangan lupa bahwa tergantung desain Anda
Activity
, yangFragments
Anda coba kerjakan mungkin atau mungkin belum ada, jadi Anda harus memperhitungkannya dengan melakukannull
pengecekan sebelum menggunakan referensi Anda.Juga, jika sebaliknya Anda bekerja dengan
FragmentStatePagerAdapter
, maka Anda tidak ingin menyimpan referensi kerasFragments
karena Anda mungkin memiliki banyak dari mereka dan referensi keras tidak perlu menyimpannya dalam memori. Sebagai gantinya simpanFragment
referensi dalamWeakReference
variabel, bukan dalam variabel standar. Seperti ini:sumber
instantiateItem
. cara yang tepat untuk melakukan ini adalah untuk memanggilinstantiateItem
dionCreate
metode aktivitas Anda dikelilingi olehstartUpdate
danfinishUpdate
. Lihat jawaban saya untuk detailnyaSaya telah menemukan jawaban atas pertanyaan saya berdasarkan posting berikut: menggunakan kembali fragmen dalam fragmentpageradapter
Beberapa hal yang telah saya pelajari:
getItem(int position)
di namaFragmentPagerAdapter
yang agak menyesatkan tentang apa metode ini sebenarnya. Ini menciptakan fragmen baru, tidak mengembalikan yang sudah ada. Artinya, metode tersebut harus diganti namanya menjadi sesuatu seperticreateItem(int position)
di Android SDK. Jadi metode ini tidak membantu kami mendapatkan fragmen.FragmentPagerAdapter
dan dengan demikian berarti Anda tidak memiliki referensi ke Fragmen atau tagnya. Jika Anda memiliki tag fragmen, Anda dapat dengan mudah mengambil referensi ke tag tersebut dariFragmentManager
dengan memanggilfindFragmentByTag()
. Kami membutuhkan cara untuk mengetahui tag dari sebuah fragmen pada posisi halaman tertentu.Larutan
Tambahkan metode helper berikut di kelas Anda untuk mengambil tag fragmen dan mengirimkannya ke
findFragmentByTag()
metode.CATATAN! Ini adalah metode identik yang
FragmentPagerAdapter
digunakan saat membuat fragmen baru. Lihat tautan ini http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104sumber
onAttach()
?Anda tidak perlu mengganti
instantiateItem
atau mengandalkan kompatibilitas denganmakeFragmentName
metode internal dengan membuat tag fragmen secara manual.instantiateItem
adalah metode publik sehingga Anda dapat dan sebenarnya harus memanggilnya dalamonCreate
metode aktivitas Anda yang dikelilingi oleh panggilan kestartUpdate
danfinishUpdate
metode seperti yang dijelaskan diPagerAdapter
javadoc :Anda kemudian dapat dengan cara di atas, menyimpan referensi ke instance fragmen Anda di vars lokal jika perlu. Lihat contoh:
instantiateItem
pertama-tama akan mencoba mendapatkan referensi ke instance fragmen yang ada dariFragmentManager
. Hanya jika mereka belum ada, itu akan membuat yang baru menggunakangetItem
metode dari adaptor Anda dan "menyimpannya" diFragmentManager
untuk penggunaan di masa mendatang.Penting untuk diperhatikan, bahwa meskipun Anda tidak perlu mendapatkan referensi ke fragmen Anda, Anda tetap harus memanggil
instantiateItem
semua tab yang dikelilingi olehstartUpdate
/finishUpdate
dalamonCreate
metode Anda seperti ini:Jika Anda tidak melakukannya, Anda berisiko bahwa instance fragmen Anda tidak akan pernah dikomit ke
FragmentManager
: saat aktivitas Anda menjadi latar depaninstantiateItem
akan dipanggil secara otomatis untuk mendapatkan fragmen Anda, tetapistartUpdate
/finishUpdate
mungkin tidak (bergantung pada detail implementasi) dan apa dasarnya lakukan adalah memulai / melakukan aFragmentTransaction
.Hal ini dapat mengakibatkan referensi ke instance fragmen yang dibuat hilang dengan sangat cepat (misalnya saat Anda memutar layar) dan dibuat ulang lebih sering dari yang diperlukan. Bergantung pada seberapa "berat" fragmen Anda, ini mungkin memiliki konsekuensi performa yang tidak dapat diabaikan.
Selain itu, dalam kasus seperti fragmen disimpan di vars lokal mungkinmenjadi basi: jika platform android mencoba mendapatkannya dari
FragmentManager
untuk alasan apa pun, itu akan gagal dan dengan demikian akan membuat dan menggunakan yang baru, sementara vars Anda masih akan mereferensikan yang lama.sumber
FragmentManager
tidak bisa begitu saja membunuh ( menghancurkan adalah kata yang tepat di sini) milik AndaFragment
(pikirkan apa yang akan terjadi jika memutuskan untuk membunuhFragment
yang sedang ditampilkan;)). Umumnya siklus hidup aFragment
terikat padanyaActivity
(lihat github.com/xxv/android-lifecycle untuk detailnya) -> aFragment
hanya dapat dimusnahkan jikaActivity
sudah dimusnahkan. Dalam kasus seperti itu ketika pengguna menavigasi kembali ke yang diberikanActivity
ituonCreate
akan dipanggil lagi dan contoh baruFragment
akan dibuat.Cara saya melakukannya adalah mendefinisikan Hashtable of WeakReferences sebagai berikut:
Kemudian saya menulis metode getItem () seperti ini:
Kemudian Anda dapat menulis metode:
Sepertinya ini bekerja dengan baik dan saya merasa sedikit kurang hack daripada
trik, karena tidak bergantung pada bagaimana FragmentPagerAdapter diimplementasikan. Tentu saja jika fragmen telah dirilis oleh FragmentPagerAdapter atau jika belum dibuat, getFragment akan mengembalikan null.
Jika ada yang menemukan sesuatu yang salah dengan pendekatan ini, komentar lebih dari diterima.
sumber
int fragmentId
harus diganti namanya menjadiint position
Saya membuat metode ini yang berfungsi untuk mendapatkan referensi ke fragmen saat ini.
sumber
solusi yang disarankan oleh @ personne3000 bagus, tetapi memiliki satu masalah: ketika aktivitas beralih ke latar belakang dan dimatikan oleh sistem (untuk mendapatkan beberapa memori
fragmentReferences
kosong ) dan kemudian dipulihkan, maka akan kosong, karenagetItem
tidak akan dipanggil.Kelas di bawah menangani situasi seperti itu:
sumber
Hambatan utama dengan mendapatkan pegangan ke fragmen adalah Anda tidak bisa mengandalkan getItem (). Setelah orientasi berubah, referensi ke fragmen akan menjadi null dan getItem () tidak dipanggil lagi.
Berikut adalah pendekatan yang tidak bergantung pada penerapan FragmentPagerAdapter untuk mendapatkan tag. Ganti instantiateItem () yang akan mengembalikan fragmen yang dibuat dari getItem () atau ditemukan dari pengelola fragmen.
sumber
Lihat postingan ini tentang mengembalikan fragmen dari FragmentPagerAdapter. Apakah mengandalkan Anda mengetahui indeks fragmen Anda - tetapi ini akan disetel di getItem () (hanya pada instantiation)
sumber
Saya berhasil menyelesaikan masalah ini dengan menggunakan id, bukan tag. (Saya menggunakan FragmentStatePagerAdapter yang saya definisikan yang menggunakan Fragmen khusus saya tempat saya mengganti metode onAttach, tempat Anda menyimpan id di suatu tempat:
Lalu Anda cukup mengakses fragmen dengan mudah di dalam aktivitas:
sumber
Saya tidak tahu apakah ini pendekatan terbaik tetapi tidak ada yang berhasil untuk saya. Semua opsi lain termasuk getActiveFragment mengembalikan null atau menyebabkan aplikasi mogok.
Saya perhatikan bahwa pada rotasi layar, fragmen sedang dilampirkan, jadi saya menggunakannya untuk mengirim fragmen kembali ke aktivitas.
Dalam fragmen:
Kemudian dalam aktivitas:
Dan terakhir di aktivitas onCreate ():
Pendekatan ini melampirkan fragmen yang terlihat ke aktivitas tanpa membuat yang baru.
sumber
Tidak yakin apakah metode saya adalah cara yang benar atau terbaik untuk melakukan ini karena saya relatif pemula dengan Java / Android, tetapi itu berhasil (saya yakin itu melanggar prinsip berorientasi objek tetapi tidak ada solusi lain yang berfungsi untuk kasus penggunaan saya).
Saya memiliki Aktivitas hosting yang menggunakan ViewPager dengan FragmentStatePagerAdapter. Untuk mendapatkan referensi ke Fragmen yang dibuat oleh FragmentStatePagerAdapter, saya membuat antarmuka callback dalam kelas fragmen:
Dalam aktivitas hosting, saya mengimplementasikan antarmuka dan membuat LinkedHasSet untuk melacak fragmen:
Dalam kelas ViewPagerFragment saya menambahkan fragmen ke daftar di dalam onAttach dan menghapusnya di dalam onDetach:
Dalam aktivitas hosting, Anda sekarang dapat menggunakan mFragments untuk melakukan iterasi melalui fragmen yang saat ini ada di FragmentStatePagerAdapter.
sumber
Kelas ini melakukan triknya tanpa bergantung pada tag internal. Peringatan: Fragmen harus diakses menggunakan metode getFragment dan bukan metode getItem.
sumber
Coba saja kode ini,
sumber