ViewModels: oddiy misol

Kirish

Ikki yil oldin, men yangi boshlanuvchilar uchun Android-da ishladim; talabalarni nol dasturlashdan birinchi Android ilovasiga olib boradigan sinf. Darsning bir qismi sifatida talabalar juda oddiy oddiy "Screen-Counter" deb nomlangan ekran ilovasini yaratadilar.

Court-Counter - bu basketbol natijalarini o'zgartiradigan tugmachalarga ega juda sodda dastur. Tayyor dasturda xato mavjud; agar siz telefonni aylantirsangiz, sizning joriy balingiz kutilmaganda yo'qoladi.

Nima gaplar? Qurilmani aylantirish - bu dasturning ishlashi davomida amalga oshirishi mumkin bo'lgan ba'zi sozlashlardan biri, jumladan klaviatura mavjudligi va qurilmaning tilini o'zgartirish. Ushbu konfiguratsiyadagi barcha o'zgarishlar Faoliyatni buzilishiga va qayta tiklanishiga olib keladi.

Ushbu xatti-harakatlar, qurilma o'z tomonida aylantirilganda, landshaft yo'nalishi bo'yicha o'ziga xos maketdan foydalanish kabi narsalarni qilishga imkon beradi. Afsuski, bu yangi (va ba'zida unchalik yangi emas) muhandislar boshlarini o'rashlari uchun bosh og'rig'i bo'lishi mumkin.

Google I / O 2017-da, Android Framework jamoasi ushbu aniq aylanish masalasi bilan shug'ullanadigan yangi arxitektura tarkibiy qismlarini taqdim etdi.

ViewModel sinfi UI bilan bog'liq ma'lumotlarni hayot aylanishi davomida saqlash va boshqarish uchun mo'ljallangan. Bu ma'lumotlar ekranning aylanishi kabi konfiguratsion o'zgarishlardan omon qolishga imkon beradi.

Ushbu post ViewModelning chekka va chekkalarini o'rgangan birinchi nashrdir. Ushbu postda:

  • ViewModels bajaradigan asosiy ehtiyojni tushuntiring
  • ViewModel-dan foydalanish uchun Counter-Counter kodini o'zgartirib, aylanish masalasini hal qiling
  • ViewModel va UI komponentlari birlashmasini diqqat bilan ko'rib chiqing

Asosiy muammo

Asosiy muammo shundan iboratki, Android Activity hayot tsiklida juda ko'p holatlar mavjud va bitta Faoliyat turli xil holatlarda konfiguratsiyani o'zgartirish tufayli ko'p marta aylanishi mumkin.

Faoliyat ushbu holatlarning barchasini bosib o'tayotganligi sababli, siz vaqtincha UI ma'lumotlarini xotirada saqlashingiz kerak bo'lishi mumkin. UI vaqtinchalik foydalanuvchi interfeysi ma'lumotlarini foydalanuvchi interfeysi uchun zarur bo'lgan ma'lumotlar sifatida aniqlamoqchiman. Bunga foydalanuvchi kiradigan ma'lumotlar, ish vaqti davomida hosil bo'lgan ma'lumotlar yoki ma'lumotlar bazasidan yuklangan ma'lumotlar kiradi. Ushbu ma'lumotlar bitmap rasmlari, RecyclerView uchun zarur bo'lgan ob'ektlar ro'yxati yoki bu holda basketbol to'pi bo'lishi mumkin.

Ilgari siz ushbu ma'lumotlarni konfiguratsiyani o'zgartirish paytida saqlashingiz va boshqa qismdan olib tashlash uchun sizRetainNonConfigurationInstance-dan foydalanishingiz mumkin. Ammo sizning ma'lumotlaringiz Faoliyat davriy holatini bilish yoki boshqarish uchun kerak bo'lmasa, bu shishib ketmaydimi? Faoliyat davomida scoreTeamA kabi o'zgaruvchiga ega bo'lishning o'rniga, va bu Faoliyat tsiklining barcha injiqliklariga bog'langan bo'lsa, agar bu ma'lumotlar Faoliyat doirasidan tashqarida boshqa joyda saqlansa nima bo'ladi? Bu ViewModel sinfining maqsadi.

Quyidagi diagrammada siz aylanishni boshlaydigan va oxirida bajariladigan Faoliyatning hayot aylanishini ko'rishingiz mumkin. ViewModelning ishlash muddati bog'liq faoliyat tsiklining yonida ko'rsatilgan. E'tibor bering, ViewModels-ni men UI kontrollerlari deb ataydigan Fragmentlar va Faoliyatlarda osongina foydalanish mumkin. Ushbu misol Faoliyat mavzusiga qaratilgan.

ViewModel siz ViewModel-ni birinchi marta so'ragan paytdan boshlab (Faoliyat on-layn yaratilganda) Harakat tugaguncha va yo'q qilinmaguncha mavjud bo'ladi. Faoliyat davomida onCreate-ga bir necha bor qo'ng'iroq qilish mumkin, masalan, ilova aylantirilganda, lekin ViewModel butun davomida saqlanib qoladi.

Juda oddiy misol

ViewModel-ni sozlash va undan foydalanishning uchta bosqichi mavjud:

  1. ViewModel-ni kengaytiradigan sinf yaratish orqali o'zingizni UI kontrolörünüzden ajratib oling
  2. ViewModel va UI boshqaruvchingiz o'rtasida aloqalarni o'rnating
  3. UI kontrolörünüzde ViewModel-dan foydalaning

1-qadam: ViewModel sinfini yarating

Eslatma: ViewModel-ni yaratish uchun birinchi navbatda hayot aylanishiga to'g'ri bog'liqlikni qo'shish kerak. Qanday qilib bu erda ko'ring.

Umuman olganda, siz ilovangizdagi har bir ekran uchun ViewModel sinfini yaratasiz. Ushbu ViewModel sinfi ekran bilan bog'liq bo'lgan barcha ma'lumotlarni o'z ichiga oladi va saqlangan ma'lumotlarga kirish va sozlovchilarga ega bo'ladi. Faoliyatlar va bo'limlaringizda amalga oshirilgan UI-ni ko'rsatish uchun kodni hozir ViewModel-da yashaydigan ma'lumotlaringizdan ajratib turadi. Shunday qilib, Court-Counter-dagi bitta ekran uchun ViewModel sinfini yarataylik:

Men ma'lumotlarni ScoreViewModel.java-da jamoat a'zolari sifatida saqlashni tanladim, ammo ma'lumotni yaxshiroq kapsüllendirmek uchun kirish va sozlovchilar yaratish yaxshi fikr.

2-qadam: UI Controller va ViewModel-ni birlashtiring

UI kontrolörünüz (aka Activity yoki Fragment) sizning ViewModelingiz haqida bilishi kerak. Bu sizning UI boshqaruvchingiz ma'lumotlarni namoyish qilishi va UI bilan o'zaro aloqalar paydo bo'lganda ma'lumotlarni yangilashi mumkin, masalan, Court-Counter-dagi jamoaning ballini oshirish uchun tugmani bosish.

Bundan tashqari ViewModels Faoliyat, Fragmentlar yoki Kontekstlarga havolani ko'rsatmasligi kerak. ** Bundan tashqari, ViewModels ko'rinishi kabi UI kontrollerlariga havolalarni o'z ichiga olmasligi kerak, chunki bu kontekstga bilvosita havolani yaratadi.

Ushbu ob'ektlarni saqlamasligingizning sababi, ViewModels sizning aniq UI kontrol instansiyalaringizni yashirishidir - agar siz faoliyatni uch marta aylantirsangiz, siz uchta turli xil Faoliyat namunalarini yaratdingiz, lekin sizda bitta ViewModel mavjud.

Shuni hisobga olib, ushbu UI kontrolör / ViewModel birlashmasini yarataylik. UI Controller-da ViewModel uchun a'zo o'zgaruvchisini yaratmoqchisiz. Keyin onCreate-da quyidagi raqamlarga qo'ng'iroq qilish kerak:

ViewModelProviders.of (). Get ( .class)

Sud hisoblagichida bu quyidagicha ko'rinadi.

** Izoh: "ViewModels-da kontekstlar mavjud emas" qoidasidan bitta istisno mavjud. Ba'zan tizim xizmatlariga o'xshash narsalar bilan ishlash uchun sizga dastur konteksti (Faoliyat kontekstidan farqli o'laroq) kerak bo'lishi mumkin. ViewModel-da ilova kontekstini saqlash yaxshi, chunki dastur konteksti dasturning tsikliga bog'liq. Bu Faoliyat tsikliga bog'langan Faoliyat kontekstidan farq qiladi. Aslida, agar siz dastur kontekstiga muhtoj bo'lsangiz, AndroidViewModel-ni kengaytirishingiz kerak, bu shunchaki dastur havolasini o'z ichiga olgan ViewModel.

3-qadam: ViewImodel-dan foydalanuvchi interfeysida foydalaning

UI ma'lumotlariga kirish yoki o'zgartirish uchun endi ViewModel-dagi ma'lumotlardan foydalanishingiz mumkin. Mana yangi onCreate usuli va A jamoasiga bir ochko qo'shib hisobni yangilash usuliga misol:

Maslahat: ViewModel shuningdek, boshqa seriyali LiveData arxitekturasi bilan juda yaxshi ishlaydi, men bu seriyani chuqur o'rganmayman. LiveData-ni ishlatishda qo'shilgan bonus - bu kuzatilishi mumkin: ma'lumotlar o'zgartirilganda UI yangilanishini boshlashi mumkin. LiveData haqida ko'proq ma'lumotni bu erda olishingiz mumkin.

ViewModelsProviders.of-ga batafsilroq qarash

Birinchi marta ViewModelProviders.of usuli MainActivity tomonidan chaqirilganda, yangi ViewModel nusxasini yaratadi. Ushbu usul qayta chaqirilganda, qachonki onCreate-ni chaqirsangiz, u muayyan sud-hisoblagichning asosiy ish faoliyati bilan bog'liq bo'lgan ViewModel-ni qaytaradi. Bu ma'lumotlarni saqlaydigan narsa.

Agar birinchi argument sifatida to'g'ri UI tekshirgichidan o'tsangiz, bu ishlaydi. Siz hech qachon UI kontrollerini ViewModel ichida saqlamasligingiz kerak, ViewModel sinfi ViewModel va UI tekshirgich inshootlari o'rtasidagi aloqalarni birinchi dalil sifatida siz kiritgan UI tekshirgichidan foydalanib kuzatadi.

ViewModelProviders.of (). Olish (ScoreViewModel.class);

Bu sizga bir xil Faoliyat yoki Fragmentning turli xil misollarini ochadigan, ammo har xil ViewModel ma'lumotiga ega bo'lgan ilovaga ega bo'lishga imkon beradi. Agar biz bir nechta basketbol o'yinlarida ochkolarni olish uchun Court-Counter-ning misolini keltirsak, tasavvur qiling. O'yinlar ro'yxatda taqdim etiladi, va keyin ro'yxatdagi o'yinni bosish bizning asosiy MainActivity-ga o'xshagan, ammo men GameScoreActivity deb nomlanadigan ekranni ochadi.

Siz ochgan har bir turli xil o'yin ekrani uchun, agar ViewModel va GameScoreActivity ni onCreate-da birlashtirsangiz, u boshqa ViewModel nusxasini yaratadi. Agar siz ushbu ekranlardan birini aylantirsangiz, ViewModel-ga ulanish saqlanib qoladi.

Ushbu mantiqning barchasi siz uchun ViewModelProviders.of (). Get ( .class) raqamingizga qo'ng'iroq qilish orqali amalga oshiriladi. Agar siz UI kontrolörünün to'g'ri nusxasida o'tsangiz, u ishlaydi.

Yakuniy fikr: ViewModels sizning UI-ni to'ldiradigan ma'lumotlardan UI kontrol kodini ajratish uchun juda mosdir. Aytishlaricha, ular ma'lumotlarning barqarorligi va ilova holatini saqlab qolish uchun davo emas. Keyingi postda Men Faoliyat siklining ViewModels bilan nozik o'zaro ta'sirini va ViewModels-ning onSaveInstanceState-ga taqqoslanishini o'rganaman.

Xulosa va qo'shimcha o'rganish

Ushbu postda men ViewModel yangi sinfining asoslarini o'rganib chiqdim. Asosiy qadamlar:

  • ViewModel sinfi UI bilan bog'liq ma'lumotlarni hayot aylanishi davomida saqlash va boshqarish uchun mo'ljallangan. Bu ma'lumotlar ekranning aylanishi kabi konfiguratsion o'zgarishlardan omon qolishga imkon beradi.
  • ViewModels UI dasturini ilovangiz ma'lumotlaridan ajratib turadi.
  • Umuman olganda, agar sizning ilovangizdagi ekran vaqtinchalik ma'lumotlarga ega bo'lsa, siz ushbu ekran ma'lumotlari uchun alohida ViewModel-ni yaratishingiz kerak.
  • ViewModel-ning hayotiy tsikllari UI boshqaruvchisi birinchi marta yaratilgan vaqtdan to u butunlay yo'q qilinmaguncha davom etadi.
  • Hech qachon UI kontrolleri yoki kontekstini ViewModel-da bevosita yoki bilvosita saqlamang. Bu ViewModel-da saqlashni o'z ichiga oladi. UI kontrolörlerine to'g'ridan-to'g'ri yoki bilvosita havolalar UI-ni ma'lumotlardan ajratish maqsadini buzadi va xotira etishmasligiga olib kelishi mumkin.
  • ViewModel ob'ektlari ko'pincha LiveData ob'ektlarini saqlaydi, ularni bu erda ko'proq bilib olishingiz mumkin.
  • ViewModelProviders.of usuli argument sifatida berilgan UI kontrolörü orqali ViewModel bilan bog'liq bo'lgan UI kontrolatorini hisobga oladi.

ViewModel-ly yaxshiligini xohlaysizmi? Tekshirib ko'rmoq:

  • Qat'iy bog'liqliklarni qo'shish bo'yicha ko'rsatmalar
  • ViewModel hujjatlari
  • ViewModel qo'llanmasi bilan xonani View va Lifecycles Codelab bilan mashq qiling

Arxitektura komponentlari sizning fikrlaringiz asosida yaratilgan. Agar sizda ViewModel yoki arxitektura tarkibiy qismlari haqida savollaringiz yoki izohlaringiz bo'lsa, fikr-mulohazalar sahifamizni ko'rib chiqing. Ushbu seriya haqida savollar yoki takliflar? Fikr qoldiring!