Memahami setRetainInstance Fragment (boolean)

341

Dimulai dengan dokumentasi:

public void setRetainInstance (boolean retain)

Kontrol apakah instance fragmen dipertahankan di seluruh penciptaan kembali Kegiatan (seperti dari perubahan konfigurasi). Ini hanya dapat digunakan dengan fragmen yang tidak ada di tumpukan belakang. Jika diatur, daur hidup fragmen akan sedikit berbeda ketika suatu aktivitas diciptakan kembali:

  • onDestroy () tidak akan dipanggil (tetapi onDetach () masih akan, karena fragmen sedang terlepas dari aktivitasnya saat ini).
  • onCreate (Bundel) tidak akan dipanggil karena fragmen tidak sedang dibuat ulang.
  • onAttach (Aktivitas) dan onActivityCreated (Bundle) masih akan dipanggil.

Saya punya beberapa pertanyaan:

  • Apakah fragmen juga mempertahankan pandangannya, atau akankah ini dibuat ulang saat konfigurasi berubah? Apa sebenarnya yang dimaksud dengan "dipertahankan"?

  • Akankah fragmen dihancurkan ketika pengguna meninggalkan aktivitas?

  • Mengapa tidak bekerja dengan fragmen di tumpukan belakang?

  • Kasus penggunaan mana yang masuk akal untuk menggunakan metode ini?

Ixx
sumber
4
pertanyaan serupa dengan info bagus: Mengapa menggunakan Fragment # setRetainInstance (boolean)?
Richard Le Mesurier

Jawaban:

348

Pertama-tama, lihat posting saya di Fragmen yang disimpan. Mungkin membantu.

Sekarang untuk menjawab pertanyaan Anda:

Apakah fragmen juga mempertahankan status tampilan , atau akankah ini dibuat ulang saat perubahan konfigurasi - apa sebenarnya "dipertahankan"?

Ya, Fragmentstatus akan dipertahankan di seluruh perubahan konfigurasi. Secara khusus, "dipertahankan" berarti bahwa fragmen tidak akan dihancurkan pada perubahan konfigurasi. Artinya, Fragmentakan dipertahankan bahkan jika perubahan konfigurasi menyebabkan yang mendasarinya Activitydihancurkan.

Akankah fragmen dihancurkan ketika pengguna meninggalkan aktivitas?

Sama seperti Activitys, Fragments dapat dihancurkan oleh sistem ketika sumber daya memori rendah. Apakah Anda memiliki fragmen Anda mempertahankan keadaan instance mereka di seluruh perubahan konfigurasi tidak akan berpengaruh pada apakah sistem akan menghancurkan atau tidak Fragmentbegitu Anda meninggalkan Activity. Jika Anda meninggalkan Activity(yaitu dengan menekan tombol beranda), huruf Fragments mungkin atau mungkin tidak dihancurkan. Jika Anda meninggalkan Activitydengan menekan tombol kembali (dengan demikian, memanggil finish()dan secara efektif menghancurkan Activity), semua yang Activityterlampir Fragmentjuga akan dihancurkan.

Mengapa tidak bekerja dengan fragmen di tumpukan belakang?

Mungkin ada beberapa alasan mengapa itu tidak didukung, tetapi alasan paling jelas bagi saya adalah bahwa Activitymemegang referensi ke FragmentManager, dan FragmentManagermengelola backstack. Artinya, tidak masalah jika Anda memilih untuk mempertahankan Fragmentatau tidak, backstack Activity(dan dengan demikian FragmentManager) akan dimusnahkan pada perubahan konfigurasi. Alasan lain mengapa itu mungkin tidak berhasil adalah karena hal-hal mungkin menjadi rumit jika kedua fragmen yang ditahan dan fragmen yang tidak disimpan dibiarkan ada di backstack yang sama.

Kasus penggunaan mana yang masuk akal untuk menggunakan metode ini?

Fragmen yang disimpan dapat sangat berguna untuk menyebarkan informasi status - terutama manajemen utas - di seluruh instance aktivitas. Misalnya, sebuah fragmen dapat berfungsi sebagai host untuk instance Threadatau AsyncTask, mengelola operasinya. Lihat posting blog saya tentang topik ini untuk informasi lebih lanjut.

Secara umum, saya akan memperlakukannya sama dengan menggunakan onConfigurationChangeddengan Activity... jangan menggunakannya sebagai bandaid hanya karena Anda terlalu malas untuk mengimplementasikan / menangani perubahan orientasi dengan benar. Hanya gunakan saat Anda perlu.

Alex Lockwood
sumber
37
Lihat objek tidak dipertahankan, mereka selalu dihancurkan pada perubahan konfigurasi.
Markus Junginger
103
Sejauh yang saya tahu, jika Anda memiliki setRetainInstance(true), Fragmentobjek java, dan semua isinya tidak dihancurkan secara rotasi, tetapi tampilan dibuat kembali. Itu onCreatedView()disebut lagi. Ini pada dasarnya cara yang seharusnya bekerja Activitiessejak Android 1.0. Saya tidak berpikir itu "malas" untuk menggunakannya, atau menggunakannya tidak "tepat". Sebenarnya saya tidak bisa melihat mengapa itu bukan default, atau mengapa Anda menginginkannya.
Timmmm
24
Saya menemukan penjelasan Anda untuk "Mengapa itu tidak bekerja dengan fragmen di tumpukan belakang?" sulit dimengerti. Tapi mungkin aku bodoh :(
HGPB
13
@dierre Suatu aktivitas dapat dihancurkan dengan berbagai cara. Misalnya, jika Anda mengklik "kembali", aktivitas akan dihancurkan. Jika Anda mengklik "beranda", aktivitas akan terhenti dan suatu saat di masa depan dapat dihancurkan ketika memori rendah. Retained Fragments hanya disimpan di seluruh perubahan konfigurasi, di mana aktivitas yang mendasarinya akan dihancurkan dan segera dibuat kembali. Dalam semua kasus lain di mana aktivitas dihancurkan, fragmen yang tersisa akan dihancurkan juga.
Alex Lockwood
3
@AlexLockwood dapatkah Anda mengkonfirmasi hal-hal berikut: Meskipun setRetainInstance(true)digunakan, orang masih harus menerapkan kegigihan mereka sendiri ( savedInstanceStateatau sebaliknya) untuk dapat menangani semua skenario: misalnya "kunci rumah, putar, kembali ke aplikasi" membuat ulang fragmen saya dengan konstruktor panggilan, kehilangan semua variabel negara. Saya memiliki AsyncTaskvariabel sebagai anggota, itu sebabnya saya ingin mempertahankan, sekarang, jika saya ingin itu berfungsi, saya terpaksa menghentikan tugas, menyimpan status, dan melanjutkan ketika pengguna kembali. Jadi semuanya, ini hanya cara cepat untuk membantu rotasi, tetapi sebaliknya tidak berguna secara umum.
TWiStErRob
28

setRetaininstancehanya berguna ketika Anda activitydihancurkan dan diciptakan kembali karena perubahan konfigurasi karena instance disimpan selama panggilan ke onRetainNonConfigurationInstance. Yaitu, jika Anda memutar perangkat, fragmen yang dipertahankan akan tetap ada di sana (tidak dihancurkan dan diciptakan kembali.) Tetapi ketika runtime membunuh aktivitas untuk mendapatkan kembali sumber daya, tidak ada yang tersisa. Ketika Anda menekan tombol kembali dan keluar dari aktivitas, semuanya hancur.

Biasanya saya menggunakan fungsi ini untuk mengubah orientasi waktu yang disimpan. Saya telah mengunduh banyak Bitmap dari server dan masing-masing 1MB, ketika pengguna secara tidak sengaja memutar perangkatnya, saya tentu tidak ingin melakukan semua pekerjaan pengunduhan lagi. Saya membuat Fragmentholding bitmap saya dan menambahkannya ke manajer dan panggilan setRetainInstance, semua Bitmap masih ada bahkan jika orientasi layar berubah.

suitianshi
sumber
Apakah Anda membuat fragmen "Hanya Data" (tanpa widget apa pun) hanya sebagai dudukan untuk Anda bitmap atau dapatkah fragmen tersebut memiliki widget juga? Saya sudah membaca sesuatu tentang bahaya menghasilkan kebocoran memori ketika fragmen berisi sesuatu yang berkaitan dengan konteks / Aktivitas ...
hgoebl
Kerangka kerja akan menghapus mActivityreferensi untuk Anda. Tapi saya tidak tahu apakah runtime juga akan menghapus widget dalam contoh fragmen dalam kasus ini. Silakan coba atau selami kode sumbernya.
suitianshi
Contoh yang bagus ketika kita dapat menggunakan setRetaininstance
Mu Sa
12

SetRetainInstance (true) memungkinkan jenis fragmen bertahan. Anggotanya akan dipertahankan selama perubahan konfigurasi seperti rotasi. Tetapi masih bisa terbunuh ketika aktivitas terbunuh di latar belakang. Jika aktivitas yang mengandung di latar belakang dibunuh oleh sistem, itu instanceState harus disimpan oleh sistem yang Anda tangani diSaveInstanceState dengan benar. Dengan kata lain onSaveInstanceState akan selalu dipanggil. Meskipun onCreateView tidak akan dipanggil jika SetRetainInstance benar dan fragmen / aktivitas belum terbunuh, masih akan dipanggil jika itu dibunuh dan sedang dicoba untuk dibawa kembali.

Berikut ini beberapa analisis aktivitas / fragmen android yang harap dapat membantu. http://ideaventure.blogspot.com.au/2014/01/android-activityfragment-life-cycle.html

Kejun Xia
sumber
7
Saya pasti melihat onCreateView dipanggil lagi pada fragmen yang dipertahankan saat memutar layar.
aij
Apakah tautan ini adalah blog Anda sendiri? Anda harus menjelaskannya jika itu masalahnya.
Flexo
4

setRetainInstance () - Sudah usang

Sebagai Fragmen Versi 1.3.0-alpha01

Metode setRetainInstance () pada Fragmen telah ditinggalkan. Dengan diperkenalkannya ViewModels, pengembang memiliki API khusus untuk mempertahankan status yang dapat dikaitkan dengan grafik Aktivitas, Fragmen, dan Navigasi. Hal ini memungkinkan pengembang untuk menggunakan Fragmen yang normal, tidak disimpan, dan menjaga keadaan spesifik yang mereka inginkan tetap terpisah, menghindari sumber kebocoran yang umum sambil mempertahankan properti yang berguna dari penciptaan tunggal dan penghancuran keadaan dipertahankan (yaitu, pembangun ViewModel dan panggilan balik onCleared () yang diterimanya).

Gastón Saillén
sumber
2

setRetainInstance (boolean) berguna ketika Anda ingin memiliki beberapa komponen yang tidak terkait dengan siklus hidup aktivitas. Teknik ini digunakan misalnya oleh rxloader untuk "menangani siklus hidup aktivitas Android untuk rxjava's Observable" (yang saya temukan di sini ).

Marian Paździoch
sumber