Ringkasan masalah
Catatan: Dalam jawaban ini saya akan merujuk FragmentPagerAdapter
dan kode sumbernya. Tetapi solusi umum juga harus diterapkan FragmentStatePagerAdapter
.
Jika Anda membaca ini, Anda mungkin sudah tahu bahwa FragmentPagerAdapter
/ FragmentStatePagerAdapter
dimaksudkan untuk dibuat Fragments
untuk Anda ViewPager
, tetapi setelah rekreasi Aktivitas (baik dari rotasi perangkat atau sistem yang mematikan Aplikasi Anda untuk mendapatkan kembali memori), ini Fragments
tidak akan dibuat lagi, tetapi contoh diambil dariFragmentManager
. Sekarang katakan Activity
kebutuhan Anda untuk mendapatkan referensi tentang ini Fragments
untuk mengerjakannya. Anda tidak memiliki id
atau tag
untuk ini dibuat Fragments
karena FragmentPagerAdapter
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 memanggil FragmentManager.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 mengubah tag
struktur yang akan merusak kode Anda sehingga Anda tidak dapat menemukan referensi ke yang sudah ada Fragments
.
Solusi alternatif tanpa mengandalkan internal tag
Berikut adalah contoh sederhana tentang cara mendapatkan referensi ke yang Fragments
dikembalikan oleh FragmentPagerAdapter
yang tidak bergantung pada tags
kumpulan internal di Fragments
. Kuncinya adalah mengganti instantiateItem()
dan menyimpan referensi di sana, bukan di getItem()
.
public class SomeActivity extends Activity {
private FragmentA m1stFragment;
private FragmentB m2ndFragment;
// other code in your Activity...
private class CustomPagerAdapter extends FragmentPagerAdapter {
// other code in your custom FragmentPagerAdapter...
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won't be called again).
switch (position) {
case 0:
return new FragmentA();
case 1:
return new FragmentB();
default:
// This should never happen. Always account for each position above
return null;
}
}
// Here we can finally safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger). Simply save the returned Fragment from
// super.instantiateItem() into an appropriate reference depending
// on the ViewPager position.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// save the appropriate reference depending on position
switch (position) {
case 0:
m1stFragment = (FragmentA) createdFragment;
break;
case 1:
m2ndFragment = (FragmentB) createdFragment;
break;
}
return createdFragment;
}
}
public void someMethod() {
// do work on the referenced Fragments, but first check if they
// even exist yet, otherwise you'll get an NPE.
if (m1stFragment != null) {
// m1stFragment.doWork();
}
if (m2ndFragment != null) {
// m2ndFragment.doSomeWorkToo();
}
}
}
atau jika Anda lebih memilih untuk bekerja dengan tags
daripada variabel anggota kelas / referensi ke Fragments
Anda juga dapat mengambil tags
set dengan FragmentPagerAdapter
dengan cara yang sama: CATATAN: ini tidak berlaku FragmentStatePagerAdapter
karena tidak diatur tags
saat membuat its Fragments
.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// get the tags set by FragmentPagerAdapter
switch (position) {
case 0:
String firstTag = createdFragment.getTag();
break;
case 1:
String secondTag = createdFragment.getTag();
break;
}
// ... save the tags somewhere so you can reference them later
return createdFragment;
}
Perhatikan bahwa metode ini TIDAK bergantung pada peniruan tag
set internal oleh FragmentPagerAdapter
dan sebagai gantinya menggunakan API yang tepat untuk mengambilnya. Dengan cara ini meskipun tag
perubahan di versi mendatang SupportLibrary
Anda akan tetap aman.
Jangan lupa bahwa tergantung desain Anda Activity
, yang Fragments
Anda coba kerjakan mungkin atau mungkin belum ada, jadi Anda harus memperhitungkannya dengan melakukan null
pengecekan sebelum menggunakan referensi Anda.
Juga, jika sebaliknya Anda bekerja dengan FragmentStatePagerAdapter
, maka Anda tidak ingin menyimpan referensi keras Fragments
karena Anda mungkin memiliki banyak dari mereka dan referensi keras tidak perlu menyimpannya dalam memori. Sebagai gantinya simpan Fragment
referensi dalam WeakReference
variabel, bukan dalam variabel standar. Seperti ini:
WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
// reference hasn't been cleared yet; do work...
}