Pada titik tertentu, saya memperhatikan pembicaraan berkala tentang bagaimana
ViewModel sebenarnya bekerja dari komponen arsitektur Google. Menyadari bahwa saya sendiri tidak mengerti, saya naik ke Internet dan terkejut menemukan bahwa ada banyak artikel identik yang luar biasa tentang cara memasak ViewModel, berteman dengan LiveData, menyelipkan dependensi melalui Belati, bersenggama dengan RxJava dan judul lain dengan berbagai tingkat kegunaan, Namun, hampir tidak ada apa-apa tentang apa yang terjadi di dalam.
Jadi saya akan mencoba mengisi celah sendiri.
Perhatian
TL; DR jika Anda merasa kasihan dengan waktu - gulung ke output, Anda akan kehilangan sedikit.
Jadi hal pertama yang dapat Anda perhatikan adalah bahwa ada 2 paket komponen arsitektur yang berbeda dengan ViewModel, yaitu:
1)
Android.arch.lifecycle lama
2)
Androidx.lifecycle baru
Spoiler : Tidak ada banyak perbedaan di antara mereka.
Semua pekerjaan ada di balik tantangan:
ViewModelProviders.of(activity).get(MyViewModel::class.java)
Mari kita mulai dengan metode
public static ViewModelProvider of(@NonNull FragmentActivity activity) { return of(activity, null); } public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { Application application = checkApplication(activity); if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } return new ViewModelProvider(ViewModelStores.of(activity), factory); }
checkApplication hanya memeriksa null, dan
AndroidViewModelFactory hanyalah singleton yang aman yang menampung Aplikasi. Jadi mereka tidak menarik, yang paling menarik adalah dalam metode
ViewModelStores.of :
public static ViewModelStore of(@NonNull FragmentActivity activity) { if (activity instanceof ViewModelStoreOwner) { return ((ViewModelStoreOwner) activity).getViewModelStore(); } return holderFragmentFor(activity).getViewModelStore(); }
Pada pandangan pertama, ini terlihat agak aneh - mengapa
FragmentActivity harus memeriksa keberadaan antarmuka
ViewModelStoreOwner jika
sudah mengimplementasikannya ? - Ini tidak selalu terjadi - hingga Februari 2018 yang jauh, ketika
perpustakaan Dukungan versi
27.1.0 dirilis , FragmentActivity tidak pernah mengimplementasikan ViewModelStoreOwner. Pada saat yang sama, ViewModel bekerja untuk dirinya sendiri.
Jadi mari kita mulai dengan
kasing lama - metode
holderFragmentFor diluncurkan :
public static HolderFragment holderFragmentFor(FragmentActivity activity) { return sHolderFragmentManager.holderFragmentFor(activity); }
Selanjutnya, dapatkan atau buat fragmen
pemegang baru:
HolderFragment holderFragmentFor(FragmentActivity activity) { FragmentManager fm = activity.getSupportFragmentManager(); HolderFragment holder = findHolderFragment(fm); if (holder != null) { return holder; } holder = mNotCommittedActivityHolders.get(activity); if (holder != null) { return holder; } if (!mActivityCallbacksIsAdded) { mActivityCallbacksIsAdded = true; activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks); } holder = createHolderFragment(fm); mNotCommittedActivityHolders.put(activity, holder); return holder; }
Nah,
HolderFragment sendiri
, tentu saja,
tetap dipertahankan public HolderFragment() { setRetainInstance(true); }
Sebenarnya, objek
ViewModelStore disimpan di dalamnya, yang pada gilirannya memiliki bundel
ViewModel :
public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap<>(); final void put(String key, ViewModel viewModel) { ViewModel oldViewModel = mMap.put(key, viewModel); if (oldViewModel != null) { oldViewModel.onCleared(); } } final ViewModel get(String key) { return mMap.get(key); } public final void clear() { for (ViewModel vm : mMap.values()) { vm.onCleared(); } mMap.clear(); } }
Mari kita kembali ke kasus ketika versi perpustakaan Dukungan 27.1.0 dan lebih tinggi. FragmentActivity sudah mengimplementasikan antarmuka ViewModelStoreOwner, yaitu hanya
mengimplementasikan metode
getViewModelStore :
public ViewModelStore getViewModelStore() { if (this.getApplication() == null) { throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call."); } else { if (this.mViewModelStore == null) { FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance(); if (nc != null) { this.mViewModelStore = nc.viewModelStore; } if (this.mViewModelStore == null) { this.mViewModelStore = new ViewModelStore(); } } return this.mViewModelStore; } }
Di sini saya akan menyederhanakan sedikit -
NonConfigurationIn Situ adalah objek yang tidak harus bergantung pada konfigurasi (jelas dari namanya), yang terletak di
Activity dan menyapu di dalam
ActivityClientRecord melalui
ActivityThread selama rekreasi antara
onStop dan
onDestroySecara umum, ini terlihat sangat lucu - daripada hack kehidupan dengan transfer ViewModel di dalam fragmen
penahan , para pengembang membuat langkah rumit - mereka menggunakan mekanisme yang persis sama, tetapi menyingkirkan kebutuhan untuk membuat fragmen tambahan setiap kali.
Aktivitas selalu memiliki metode
onRetainNonConfigurationInstance yang menarik. Di kelas Activity, dia pada dasarnya tidak melakukan apa pun. Secara umum:
public Object onRetainNonConfigurationInstance() { return null; }
Deskripsi dalam dokumentasi ini menjanjikan:
Disebut oleh sistem, sebagai bagian dari menghancurkan suatu aktivitas karena perubahan konfigurasi, ketika diketahui bahwa instance baru akan segera dibuat untuk konfigurasi baru. Anda dapat mengembalikan objek apa pun yang Anda suka di sini, termasuk instance aktivitas itu sendiri, yang nantinya dapat diambil dengan memanggil getLastNonConfigurationInstance () dalam instance aktivitas baru.

Artinya, apa yang tidak dimasukkan ke sana - itu akan merangkak keluar di
getLastNonConfigurationInstance () setelah membuat ulang Activity. Pengembang komponen arsitektur mengambil keuntungan dari ini. Dari minus - hingga 4 android tidak bekerja, itu akan diperlukan dengan cara lama melalui mempertahankan fragmen.
Metode ViewModel yang
jelas () disebut sangat sederhana - dalam metode
onDestroy FragmentActivity.
protected void onDestroy() { super.onDestroy(); if (this.mViewModelStore != null && !this.isChangingConfigurations()) { this.mViewModelStore.clear(); } this.mFragments.dispatchDestroy(); }
Bahkan, dengan Androidx hampir semuanya sama, satu-satunya perbedaan adalah bahwa metode getViewModelStore () tidak lagi di FragmentActivity, tetapi di
ComponentActivity , dari mana FragmentActivity diwarisi di AndroidX. Hanya panggilan ke metode clear () yang telah berubah; telah dihapus dari onDestroy menjadi panggilan balik independen, yang dibuat di konstruktor ComponentActivity:
getLifecycle().addObserver(new GenericLifecycleObserver() { @Override public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) { if (event == Lifecycle.Event.ON_DESTROY) { if (!isChangingConfigurations()) { getViewModelStore().clear(); } } } });
Untuk protokol - selama pembuatan artikel berikut digunakan:
Perpustakaan dukungan 27.0.0, 28.0.0
androidx.lifecycle: lifecycle-viewmodel: 2.0.0
androidx.lifecycle: lifecycle-extensions: 2.0.0
android.arch.lifecycle: extensions: 1.1.1
android.arch.lifecycle: viewmodel: 1.1.1
Kesimpulan:
- ViewModel benar-benar selamat dari rekreasi aktivitas dalam fragmen penahan hingga perpustakaan dukungan 27.1.0 yang muncul pada Februari 2018
- Dari
pustaka Dukungan versi
27.1.0 dan seterusnya, serta dalam
AndroidX ViewModel, saya pergi menunggu untuk membuat kembali Activity in
FragmentActivity.NonConfigurationInstances (
ComponentActivity.NonConfigurationInstansi untuk AndroidX), sebenarnya mekanisme yang sama yang melaluinya tetap menggunakan fragmen, tetapi membuat sebuah fragmen tambahan tidak diperlukan, tetapi sebenarnya membuat fragmen tambahan tidak diperlukan. , semua ViewModel dikirim "di samping" dengan mempertahankan fragmen.
- Mekanisme ViewModel hampir
sama di perpustakaan AndroidX dan Support
- Jika Anda tiba-tiba perlu (ya saya tidak bisa membayangkan mengapa) menyeret data yang seharusnya hidup saat Activity hidup tetapi
memperhitungkan rekreasi - Anda dapat menggunakan
onRetainNonConfigurationInstance () /
getLastNonConfigurationInstance () /
getLastNonConfigurationInstance ()- Apa keputusan lama, seperti apa tampilan baru antara hack yang didokumentasikan dan kruk