Jawaban utama bergantung pada nama yang dihasilkan oleh framework. Jika itu pernah berubah, maka itu tidak akan berfungsi lagi.
Bagaimana dengan solusi ini, mengesampingkan instantiateItem()
dan destroyItem()
dari Anda Fragment(State)PagerAdapter
:
public class MyPagerAdapter extends FragmentStatePagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return ...;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(...);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
Ini sepertinya bekerja untuk saya ketika berhadapan dengan Fragmen yang tersedia. Fragmen yang belum dipakai, akan mengembalikan nol saat menelepon getRegisteredFragment
. Tapi saya telah menggunakan ini sebagian besar untuk mendapatkan arus Fragment
keluar dari ViewPager
: adapater.getRegisteredFragment(viewPager.getCurrentItem())
dan ini tidak akan kembali null
.
Saya tidak mengetahui adanya kelemahan lain dari solusi ini. Jika ada, saya ingin tahu.
Fragment
dalamWeakReference
untuk menjamin Anda tidak mencegah fragmen hancur dari yang sampah yang dikumpulkan? Sepertinya hal yang tepat untuk dilakukan ...MyPagerAdapter
dihancurkan karena siklus hidup (yaitu memutar), tidakregisterdFragments
akan hilang? ApakahActivity
/Fragment
menggunakanMyPagerAdapter
harus menyimpannyaonSaveInstanceState
, dan kemudian perlu memperbaruinya denganFragmentManager
ref baru ?getItem
tidak dipanggil lagi pada rotate (untuk setiap fragmen yang sudah dibuat), karenaFragmentManager
mengembalikan status yangFragments
dipegangnya dalam pager. JikainstantiateItem
dipanggil ketika masingFragment
- masing dipulihkan, maka solusi ini sebenarnya lebih aman dan lebih banyak bukti di masa depan daripada milik saya atau jawaban yang diterima. Saya akan mempertimbangkan untuk mencoba ini sendiri.Untuk mengambil fragmen dari ViewPager ada banyak jawaban di sini dan di utas / blog SO terkait lainnya. Semua orang yang saya lihat rusak, dan mereka umumnya tampak jatuh ke dalam salah satu dari dua jenis yang tercantum di bawah ini. Ada beberapa solusi yang valid lain jika Anda hanya ingin mengambil fragmen saat ini, seperti ini jawaban lain di thread ini.
Jika menggunakan
FragmentPagerAdapter
lihat di bawah. Jika menggunakanFragmentStatePagerAdapter
nilainya melihat ini . Indeks ambil yang bukan yang sekarang di FragmentStateAdapter tidak berguna karena pada dasarnya ini akan sepenuhnya dihancurkan keluar dari tampilan / keluar dari batas offScreenLimit.JALAN YANG TIDAK SELAMAT
Salah: Pertahankan daftar fragmen internal Anda sendiri, ditambahkan ke saat
FragmentPagerAdapter.getItem()
dipanggilSparseArray
atauMap
getItem
yang disebut pertama kali halaman digulir ke (atau diperoleh jika AndaViewPager.setOffscreenPageLimit(x)
> 0) diViewPager
, jika hostingActivity
/Fragment
terbunuh atau dimulai ulang maka internalSpaseArray
akan dihapus ketika kustom FragmentPagerActivity dibuat ulang, tetapi di belakang layar, ViewPagers fragmen internal yang akan diciptakan, dangetItem
akan tidak dipanggil untuk salah satu indeks, sehingga kemampuan untuk mendapatkan fragmen dari indeks akan hilang selamanya. Anda dapat menjelaskan ini dengan menyimpan dan mengembalikan referensi fragmen ini melaluiFragmentManager.getFragment()
danputFragment
tetapi ini mulai mendapatkan IMHO berantakan.Salah: Bangun id tag Anda sendiri sesuai dengan apa yang digunakan di bawah kap
FragmentPagerAdapter
dan gunakan ini untuk mengambil fragmen halaman dariFragmentManager
ViewPager
yang dapat berubah kapan saja atau untuk versi OS apa pun.Metode yang diciptakan untuk solusi ini adalah
PATH SELAMAT:
ViewPager.instantiateItem()
Pendekatan yang mirip dengan di
getItem()
atas tetapi tidak merusak siklus adalah untuk ini adalah untuk menghubungkan keinstantiateItem()
bukangetItem()
sebagai yang pertama akan dipanggil setiap kali indeks dibuat / diakses. Lihat jawaban iniJALAN SELAMAT: Bangun sendiri
FragmentViewPager
Buat
FragmentViewPager
kelas Anda sendiri dari sumber lib dukungan terbaru dan ubah metode yang digunakan secara internal untuk membuat tag fragmen. Anda bisa menggantinya dengan yang di bawah ini. Ini memiliki keuntungan bahwa Anda tahu pembuatan tag tidak akan pernah berubah dan Anda tidak mengandalkan api / metode pribadi, yang selalu berbahaya.Kemudian seperti yang dikatakan oleh doc, ketika Anda ingin mengambil sebuah fragmen yang digunakan untuk indeks, panggil saja sesuatu seperti metode ini (yang dapat Anda masukkan ke dalam custom
FragmentPagerAdapter
atau subclass) karena menyadari hasilnya mungkin nol jika getItem belum dipanggil untuk yaitu halaman itu belum dibuat.Ini adalah solusi sederhana dan menyelesaikan masalah di dua solusi lain yang ditemukan di mana-mana di web
sumber
instantiateItem()
mana adalah ketika Anda ingin mengakses sebuah fragmen yang belum dikunjungi setelah peristiwa siklus hidup telah terjadi dan dikunjungi sebelum acara siklus hidup. Perbedaan kecil yang saya tahu tetapi salah satu yang menyebabkan bug halus dalam program saya maka saya mencari tahu ini.getItemId(pos)
di dalamFragmentStatePagerAdapter
Tambahkan metode selanjutnya ke FragmentPagerAdapter Anda:
getActiveFragment (0) harus berfungsi.
Berikut adalah solusi yang diimplementasikan ke dalam ViewPager https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d . Jika sesuatu gagal, Anda akan melihat log kerusakan yang bagus.
sumber
Solusi sederhana lain:
sumber
setPrimaryItem()
yang disebut setelahViewPager.OnPageChangeListener#onPageSelected()
saya tidak dapat menggunakannya :-(Saya tahu ini memiliki beberapa jawaban, tetapi mungkin ini akan membantu seseorang. Saya telah menggunakan solusi yang relatif sederhana ketika saya perlu mendapatkan
Fragment
dari sayaViewPager
. DiActivity
atauFragment
memegangViewPager
, Anda dapat menggunakan kode ini untuk menggilir setiapFragment
memegangnya.Jika Anda tahu posisi Anda
Fragment
diViewPager
, Anda bisa menelepongetItem(knownPosition)
.Jika Anda tidak tahu posisi Anda
Fragment
diViewPager
, Anda dapat meminta anak-anak AndaFragments
mengimplementasikan antarmuka dengan metode sepertigetUniqueId()
, dan menggunakannya untuk membedakan mereka. Atau Anda dapat menelusuri semuaFragments
dan memeriksa jenis kelas, sepertiif(viewPagerFragment instanceof FragmentClassYouWant)
!!! Sunting !!!
Saya telah menemukan bahwa
getItem
hanya dipanggil olehFragmentPagerAdapter
ketika masing-masingFragment
perlu dibuat pertama kali , setelah itu, tampaknyaFragments
yang didaur ulang menggunakanFragmentManager
. Dengan cara ini, banyak implementasiFragmentPagerAdapter
buat baruFragment
digetItem
. Menggunakan metode saya di atas, ini berarti kita akan membuat yang baruFragment
setiap kaligetItem
dipanggil saat kita menelusuri semua item dalamFragmentPagerAdapter
. Karena ini, saya telah menemukan pendekatan yang lebih baik, menggunakanFragmentManager
untuk mendapatkan masing-masingFragment
sebagai gantinya (menggunakan jawaban yang diterima). Ini adalah solusi yang lebih lengkap, dan telah bekerja dengan baik untuk saya.Dan Anda akan membutuhkan metode ini.
sumber
ViewPager
itu sendiri yang mengatur tag tersebut. Solusi ini rapuh karena bergantung pada mengetahui konvensi penamaan "tersembunyi" dariViewPager
. Jawaban Streets of Boston adalah solusi yang jauh lebih komprehensif, yang sekarang saya gunakan dalam proyek saya (bukan pendekatan ini).Untuk kasus saya, tidak ada solusi di atas yang berfungsi.
Namun karena saya menggunakan Child Fragment Manager di Fragmen, berikut ini digunakan:
Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());
Ini hanya akan berfungsi jika fragmen Anda di Manajer sesuai dengan item viewpager.
sumber
sumber
Saya menanganinya dengan terlebih dahulu membuat daftar semua fragmen (
List<Fragment> fragments;
) yang akan saya gunakan kemudian menambahkannya ke pager sehingga memudahkan untuk menangani fragmen yang saat ini dilihat.Begitu:
jadi ini bisa disebut:
jadi saya bisa membuangnya di pernyataan if yang hanya akan berjalan jika itu berada di fragmen yang benar
tapi itu hanya pendekatan hack dan slash saya tetapi berhasil untuk saya, saya menggunakannya jangan lakukan perubahan relevan untuk fragmen saya saat ini ditampilkan ketika tombol kembali ditekan.
sumber
Ini berdasarkan jawaban Steven di atas. Ini akan mengembalikan instance fragmen aktual yang sudah dilampirkan ke aktivitas induk.
sumber
Saya tidak dapat menemukan cara yang sederhana dan bersih untuk melakukan ini. Namun, widget ViewPager hanyalah ViewGroup lain, yang menampung fragmen Anda. ViewPager memiliki fragmen ini sebagai anak langsung. Jadi Anda bisa mengulanginya (menggunakan .getChildCount () dan .getChildAt ()), dan lihat apakah instance fragmen yang Anda cari saat ini dimuat ke dalam ViewPager dan dapatkan referensi untuk itu. Misalnya, Anda dapat menggunakan beberapa bidang ID unik statis untuk membedakan fragmen.
Perhatikan bahwa ViewPager mungkin tidak memuat fragmen yang Anda cari karena ini adalah wadah virtual seperti ListView.
sumber
FragmentPagerAdapter adalah pabrik fragmen. Untuk menemukan fragmen berdasarkan posisinya jika masih dalam memori gunakan ini:
Kode sampel untuk v4 mendukung api.
sumber
Anda tidak perlu menelepon
getItem()
atau metode lain di tahap selanjutnya untuk mendapatkan referensi dariFragment
host yang ada di dalamnyaViewPager
. Jika Anda ingin memperbarui beberapa data di dalamFragment
kemudian gunakan pendekatan ini: Perbarui ViewPager secara dinamis?Kuncinya adalah mengatur data baru di dalam
Adaper
dan meneleponnotifyDataSetChanged()
yang pada gilirannya akan memanggilgetItemPosition()
, memberikan Anda referensi AndaFragment
dan memberi Anda kesempatan untuk memperbaruinya. Semua cara lain mengharuskan Anda untuk tetap merujuk pada diri sendiri atau peretasan lain yang bukan solusi yang baik.sumber
getItemPosition()
adalah metode di adaptor Anda. Anda tidak akan menyebutnya secara langsung. Anda memiliki referensi adaptor Anda sehingga Anda memanggiladapter.notifyDataSetChanged()
yang pada gilirannya akan memanggilgetItemPosition()
adaptor Anda dengan melewati referensi AndaFragment
. Anda dapat melihat implementasi penuh dalam aksi di sini stackoverflow.com/questions/19891828/…Fragment
tetapi bagaimana untuk mendapatkan referensi dapat diperdebatkan. Solusi lain mendapatkan referensi dariFragmentManager
menggunakan string yang mirip"android:switcher:"+id
atau kembaliPOSITION_NONE
darigetItemosition()
menyebabkan semua fragmen dibuat ulang sendiri.Harus meluas
FragmentPagerAdapter
ke kelas adaptor ViewPager Anda.Jika Anda menggunakan
FragmentStatePagerAdapter
maka Anda tidak akan dapat menemukanFragment
dengan AndaID
Cara menggunakan metode ini: -
sumber
Hai saya telah menjawab pertanyaan ini di sini . Pada dasarnya, Anda perlu mengganti
metode FragmentStatePagerAdapter.
sumber
Solusi terbaik adalah dengan menggunakan ekstensi yang kami buat di CodePath yang disebut SmartFragmentStatePagerAdapter . Mengikuti panduan itu, ini membuat pengambilan fragmen dan fragmen yang saat ini dipilih dari ViewPager secara signifikan lebih mudah. Itu juga melakukan pekerjaan yang lebih baik mengelola memori fragmen yang tertanam dalam adaptor.
sumber
Cara termudah dan paling ringkas. Jika semua fragmen Anda
ViewPager
berasal dari kelas yang berbeda, Anda dapat mengambil dan membedakannya sebagai berikut:sumber
Saya menerapkan ini dengan mudah dengan pendekatan yang sedikit berbeda.
Metode FragmentAdapter.getItem kustom saya mengembalikan bukan MyFragment baru (), tetapi contoh MyFragment yang dibuat dalam konstruktor FragmentAdapter.
Dalam aktivitas saya, saya kemudian mendapatkan fragmen dari adaptor, periksa apakah itu instance dari fragmen yang diperlukan, lalu cor dan gunakan metode yang diperlukan.
sumber
Buat id sumber daya integer di /values/integers.xml
Kemudian dalam fungsi getItem PagerAdapter:
Kemudian dalam aktivitas menulis fungsi ini untuk mendapatkan referensi fragmen:
Dapatkan referensi fragmen dengan memanggil fungsi di atas dan kemudian serahkan ke fragmen khusus Anda:
sumber
Cara mudah untuk beralih pada fragmen di manajer fragmen. Temukan viewpager, yang memiliki argumen posisi bagian, ditempatkan di newInstance PlaceholderFragment statis publik (int sectionNumber) .
sumber
Dalam Fragmen
Dalam FragmentActivity
sumber
di TabLayout ada beberapa tab untuk Fragment. Anda dapat menemukan fragmen dengan Tag menggunakan indeks fragmen.
Misalnya indeks untuk Fragment1 adalah 0, jadi dalam
findFragmentByTag()
metode, lulus tag untuk Viewpager. Setelah menggunakan fragmentTransaction Anda dapat menambahkan, ganti fragmen.String tag = "android:switcher:" + R.id.viewPager + ":" + 0; Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);
sumber
Ok untuk adaptor
FragmentStatePagerAdapter
saya mendanai solusi:di FragmentActivity Anda:
dan buat sebuah metode di kelas Anda FragmentActivity - Sehingga metode itu memberi Anda akses ke Fragmen Anda, Anda hanya perlu memberikannya posisi fragmen yang Anda inginkan:
di Adaptor Anda:
sumber
index
adalah tempat fragmen dalam adaptor seperti yang Anda tambahkanfragment1
dulu sehingga retreivefragment1
passindex
sebagai 0 dan seterusnya untuk istirahatsumber