Saya telah menulis aktivitas boneka yang beralih di antara dua fragmen. Ketika Anda pergi dari FragmentA ke FragmentB, FragmentA ditambahkan ke tumpukan belakang. Namun, ketika saya kembali ke FragmentA (dengan menekan kembali), FragmentA yang sama sekali baru dibuat dan keadaan tempatnya hilang. Saya merasa bahwa saya mencari hal yang sama dengan pertanyaan ini , tetapi saya telah memasukkan contoh kode lengkap untuk membantu membasmi masalah:
public class FooActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(android.R.id.content, new FragmentA());
transaction.commit();
}
public void nextFragment() {
final FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(android.R.id.content, new FragmentB());
transaction.addToBackStack(null);
transaction.commit();
}
public static class FragmentA extends Fragment {
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View main = inflater.inflate(R.layout.main, container, false);
main.findViewById(R.id.next_fragment_button).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
((FooActivity) getActivity()).nextFragment();
}
});
return main;
}
@Override public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save some state!
}
}
public static class FragmentB extends Fragment {
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.b, container, false);
}
}
}
Dengan beberapa pesan log ditambahkan:
07-05 14:28:59.722 D/OMG ( 1260): FooActivity.onCreate
07-05 14:28:59.742 D/OMG ( 1260): FragmentA.onCreateView
07-05 14:28:59.742 D/OMG ( 1260): FooActivity.onResume
<Tap Button on FragmentA>
07-05 14:29:12.842 D/OMG ( 1260): FooActivity.nextFragment
07-05 14:29:12.852 D/OMG ( 1260): FragmentB.onCreateView
<Tap 'Back'>
07-05 14:29:16.792 D/OMG ( 1260): FragmentA.onCreateView
Itu tidak pernah memanggil FragmentA.onSaveInstanceState dan itu menciptakan FragmentA baru ketika Anda menekan kembali. Namun, jika saya menggunakan FragmentA dan saya mengunci layar, FragmentA.onSaveInstanceState dipanggil. Sangat aneh ... apakah saya salah mengharapkan fragmen yang ditambahkan ke tumpukan belakang tidak perlu dibuat ulang? Inilah yang dikatakan dokumen :
Sedangkan, jika Anda memanggil addToBackStack () saat menghapus sebuah fragmen, maka fragmen tersebut dihentikan dan akan dilanjutkan jika pengguna menavigasi kembali.
ListView
. Sepertinya terlalu banyak omong kosong untuk melampirkan pendengar gulir dan memperbarui variabel instan.Jawaban:
Jika Anda kembali ke fragmen dari tumpukan belakang, ia tidak membuat ulang fragmen tetapi menggunakan kembali contoh yang sama dan mulai dengan
onCreateView()
siklus hidup fragmen, lihat Siklus hidup fragmen .Jadi jika Anda ingin menyimpan state Anda harus menggunakan variabel instan dan tidak bergantung
onSaveInstanceState()
.sumber
Dibandingkan dengan Apple
UINavigationController
danUIViewController
, Google tidak melakukan dengan baik dalam arsitektur perangkat lunak Android. Dan dokumen Android tentangFragment
tidak banyak membantu.Saat Anda memasukkan FragmentB dari FragmentA, instance FragmentA yang ada tidak dihancurkan. Saat Anda menekan Kembali di FragmentB dan kembali ke FragmentA, kami tidak membuat instance FragmentA baru. Instance FragmentA yang ada
onCreateView()
akan dipanggil.Kuncinya adalah kita tidak harus mengembang tampilan lagi di FragmentA
onCreateView()
, karena kita menggunakan instance FragmentA yang ada. Kita perlu menyimpan dan menggunakan kembali rootView.Kode berikut berfungsi dengan baik. Itu tidak hanya menjaga keadaan fragmen, tetapi juga mengurangi beban RAM dan CPU (karena kami hanya mengembang tata letak jika perlu). Saya tidak percaya kode sampel dan dokumen Google tidak pernah menyebutkannya tetapi selalu mengembang tata letak .
Versi 1 (Jangan gunakan versi 1. Gunakan versi 2)
------ Pembaruan pada 3 Mei 2005: -------
Seperti komentar yang disebutkan, terkadang
_rootView.getParent()
nullonCreateView
, yang menyebabkan crash. Versi 2 menghapus _rootView di onDestroyView (), seperti yang disarankan dell116. Diuji pada Android 4.0.3, 4.4.4, 5.1.0.Versi 2
PERINGATAN!!!
Ini adalah HACK! Meskipun saya menggunakannya di aplikasi saya, Anda perlu menguji dan membaca komentar dengan cermat.
sumber
Saya kira ada cara alternatif untuk mencapai apa yang Anda cari. Saya tidak mengatakan ini solusi yang lengkap tetapi melayani tujuan dalam kasus saya.
Apa yang saya lakukan adalah bukannya mengganti fragmen yang saya tambahkan fragmen target. Jadi pada dasarnya Anda akan menggunakan
add()
metode sebagai gantinyareplace()
.Apa lagi yang saya lakukan. Saya menyembunyikan fragmen saya saat ini dan juga menambahkannya ke backstack.
Oleh karena itu tumpang tindih fragmen baru atas fragmen saat ini tanpa merusak pandangannya. (Periksa bahwa
onDestroyView()
metodenya tidak disebut. Ditambah menambahkannya untukbackstate
memberi saya keuntungan dari melanjutkan fragmen.Ini kodenya:
Sistem AFAIK hanya memanggil
onCreateView()
jika tampilan dihancurkan atau tidak dibuat. Tapi di sini kita telah menyimpan tampilan dengan tidak melepasnya dari memori. Jadi itu tidak akan membuat tampilan baru.Dan ketika Anda kembali dari Fragmen Tujuan, itu akan muncul terakhir
FragmentTransaction
fragmen atas menghapus yang akan membuat tampilan paling atas (SourceFragment) muncul di layar.KOMENTAR: Seperti yang saya katakan itu bukan solusi lengkap karena tidak menghapus tampilan fragmen Sumber dan karenanya menempati lebih banyak memori daripada biasanya. Namun tetap, melayani tujuan. Kami juga menggunakan mekanisme yang sama sekali berbeda untuk menyembunyikan tampilan alih-alih menggantinya yang non tradisional.
Jadi itu bukan untuk bagaimana Anda mempertahankan negara, tetapi untuk bagaimana Anda mempertahankan pandangan.
sumber
Activity A{Fragment A --> Fragment B}
ketika saya meluncurkan aplikasi lagi setelah menekan tombol home kedua fragmenonResume()
dipanggil dan karenanya mereka memulai polling mereka. Bagaimana saya bisa mengendalikan ini?Saya akan menyarankan solusi yang sangat sederhana.
Ambil variabel Lihat referensi dan atur tampilan di OnCreateView. Periksa apakah tampilan sudah ada dalam variabel ini, lalu kembali tampilan yang sama.
sumber
if (_rootView.getParent() != null) { ((ViewGroup)_rootView.getParent()).removeView(_rootView); }
apakah pantas untuk mengosongkan memori?null
kefragmentView
variabel dalamonDestroy()
metode.onDestroyView()
. Kliring ini tidak terjadi untuk variabel tampilan cadangan kami (di sinifragmentView
) dan itu akan menyebabkan kebocoran memori ketika fragmen kembali ditumpuk / dihancurkan. Anda dapat menemukan referensi yang sama di [Penyebab umum kebocoran memori] ( square.github.io/leakcanary/fundamentals/… ) di pengantar LeakCanery.Saya menemukan masalah ini dalam Fragmen yang berisi peta, yang memiliki terlalu banyak detail pengaturan untuk disimpan / dimuat ulang. Solusi saya adalah pada dasarnya menjaga Fragmen ini tetap aktif sepanjang waktu (mirip dengan apa yang disebutkan @kaushal).
Katakanlah Anda memiliki Fragmen A saat ini dan ingin menampilkan Fragmen B. Ringkas konsekuensinya:
Oleh karena itu, jika Anda ingin menjaga kedua Fragmen "disimpan", alihkan saja menggunakan hide () / show ().
Kelebihan : metode mudah dan sederhana untuk membuat beberapa Fragmen tetap berjalan
Kontra : Anda menggunakan lebih banyak memori untuk membuat semuanya tetap berjalan. Dapat mengalami masalah, misalnya menampilkan banyak bitmap besar
sumber
onSaveInstanceState()
hanya dipanggil jika ada perubahan konfigurasi.Sejak mengubah dari satu fragmen ke fragmen lain, tidak ada konfigurasi yang berubah jadi tidak ada panggilan
onSaveInstanceState()
sana. Status apa yang tidak disimpan? Bisakah Anda menentukan?Jika Anda memasukkan beberapa teks dalam EditText, teks itu akan disimpan secara otomatis. Item UI apa pun tanpa ID apa pun adalah item yang status pandangannya tidak akan disimpan.
sumber
onSaveInstanceState()
disebut juga ketika sistem menghancurkan Activity karena kekurangan sumber daya.Di sini, karena
onSaveInstanceState
dalam fragmen tidak memanggil ketika Anda menambahkan fragmen ke backstack. Siklus hidup fragmen di backstack ketika dipulihkan mulaionCreateView
dan berakhironDestroyView
sementaraonSaveInstanceState
disebut antaraonDestroyView
danonDestroy
. Solusi saya adalah membuat variabel instan dan init dionCreate
. Kode sampel:Dan periksa di
onActivityCreated
:sumber
sumber
Masalah saya serupa tetapi saya mengatasi saya tanpa menjaga fragmen tetap hidup. Misalkan Anda memiliki aktivitas yang memiliki 2 fragmen - F1 dan F2. F1 dimulai pada awalnya dan katakanlah di berisi beberapa info pengguna dan kemudian pada kondisi tertentu F2 muncul pada meminta pengguna untuk mengisi atribut tambahan - nomor telepon mereka. Selanjutnya, Anda ingin nomor telepon itu muncul kembali ke F1 dan menyelesaikan pendaftaran tetapi Anda menyadari bahwa semua informasi pengguna sebelumnya hilang dan Anda tidak memiliki data sebelumnya. Fragmen dibuat kembali dari awal dan bahkan jika Anda menyimpan informasi ini dalam
onSaveInstanceState
bundel kembali nolonActivityCreated
.Solusi: Simpan informasi yang diperlukan sebagai variabel instan dalam aktivitas panggilan. Kemudian masukkan variabel instance ke dalam fragmen Anda.
Jadi berikut dengan contoh saya: sebelum saya menampilkan F2 saya menyimpan data pengguna dalam variabel instan menggunakan panggilan balik. Lalu saya mulai F2, pengguna mengisi nomor telepon dan menekan simpan. Saya menggunakan panggilan balik lain dalam aktivitas, mengumpulkan informasi ini dan mengganti fragmen F1 saya, kali ini memiliki data paket yang dapat saya gunakan.
Informasi lebih lanjut tentang panggilan balik dapat ditemukan di sini: https://developer.android.com/training/basics/fragments/communicating.html
sumber
sumber
Ganti Fragmen menggunakan kode berikut:
Aktivitas diBackPressed () adalah:
sumber
sumber
Solusi sempurna yang menemukan fragmen lama di tumpukan dan memuatnya jika ada di tumpukan.
gunakan seperti
sumber