Az mvvm használatának leállítása

Az mvvm használatának leállítása

Mindazok számára, akiket a Databinding Könyvtár kerestetett, és akik úgy döntöttek, hogy elkészítik az alkalmazást az MVVM-re, bátor emberek vagytok!

Databinding könyvtár

A Databinding könyvtár kezelésének megkezdése. Az volt a benyomásom. Azok, akik már ismerik, megértenek engem, de a többiek számára ez az, amit a könyvtár munkája néz ki:

Az mvvm használatának leállítása

A Databinding Library használata lehetővé teszi:

  • Megszabadulhat a findViewById és a setOnClickListener hívásoktól. Ez azt jelenti, hogy meg kell adni az xml idét. a nézethez a kötelező érvényű. viewId. A módszerhívásokat közvetlenül az xml-ből is beállíthatja;
  • Az adatok közvetlen összekapcsolása a nézetelemekkel. Úgy hívjuk a binding.setUser (felhasználó) nevet. és az xml-ben megadjuk például az android: text = "@";
  • Hozzon létre egyéni attribútumokat. Ha például képeket szeretne betölteni az ImageView programba a Picasso könyvtár segítségével, létrehozhat egy kötegadaptert a "imageUrl" attribútumhoz, és az xml írási kötésben: url = "@".
    Egy ilyen kötőadapter így fog kinézni:
  • Állítsa be a nézet állapotát az adatoktól. Például, hogy megjelenik-e a letöltési jelző, attól függ, hogy van-e adat.
  • Az utolsó pont különösen kellemes számomra, mert az államok mindig is nehéz témát jelentettek. Ha három állapotot kell megjeleníteni a képernyőn (letöltés, adat, hiba), akkor rendben van. De ha vannak különböző követelmények elemek állapota adatoktól függően (például, hogy a szöveg csak akkor, ha nem üres, vagy színe megváltozik értékétől függően), akkor szükség lehet egy nagy kapcsolóval együtt minden lehetséges változatát interfész államok, vagy sok zászlók és kód az elemek értékének beállítási módjaiban.
    Ezért az a tény, hogy a Databinding könyvtár megkönnyíti az államokkal való együttműködést, óriási plusz. Például írj xml android: visibility = "@". Nem tudhatjuk többé, mikor kell elrejteni vagy megjeleníteni a TextView felhasználónevet. Mi csak megadjuk a nevet, és a láthatóság automatikusan megváltozik.

    De azáltal, hogy aktívan használja az adatbevitelt, egyre több kódot kapsz xml-ben. És annak érdekében, hogy az elrendezést ne alakítsuk ki egy dump-ba, létre fogunk hozni egy osztályt, amelyben e kódot fogjuk származni. Az xml-ben csak a tulajdonságok hívása lesz. Adok egy kis példát. Tegyük fel, hogy van egy felhasználói osztály:

    Az UI-ban szeretnénk látni a teljes nevet, és írnunk kell az xml-be:

    Ez nem nagyon kívánatos az xml-ben. és létrehozunk egy osztályt, amelyben elviseljük ezt a logikát:

    A könyvtár alkotói azt javasolják, hogy az ilyen osztályokat hívják meg (mint az MVVM mintában, meglepő módon).

    A példában az osztály öröklődik a BaseObservable-ból, és a bejelentkező kódban a notifyPropertyChanged () nevű kódot használja, de ez nem az egyetlen mód. Az ObservableField mezőket is befedheti, és a függő UI elemek automatikusan frissülnek. De úgy vélem, hogy ez a módszer kevésbé rugalmas és ritkán használja.

    Most az xml-ben lesz:

    Sokkal jobb, nem igaz?

    Tehát van egy ViewModel osztály, amely rétegként működik az adatok és a nézet között. Az adatkonverziókkal foglalkozik, ellenőrzi, mely mezők (és a kapcsolódó UI-elemek), és ha frissülnek, azt a logikát tartalmazza, hogy az egyik mező a többiektől függ. Ezzel törölheti az xml kódot. Ezenkívül kényelmesen használhatja ezt az osztályt a nézetek eseményeinek kezelésére (sajtolás stb.).

    És akkor a gondolat jön hozzánk: Ha már van adatbevitelünk. van egy ViewModel osztály, amely tartalmazza a megjelenítési logikát, akkor miért nem használja az MVVM mintát?

    Ez a gondolat elkerülhetetlenül jön. Mert a mi pillanatunkban nagyon, nagyon közel áll az MVVM mintához. Vessünk egy rövid pillantást.

    A Model-View-ViewModel mintában három fő összetevő található:

    • Modell. Az alkalmazás üzleti logikája, amely megjeleníti az adatokat.
    • View. Felelős a felhasználó által a képernyőn megjelenő összes felhasználói elem megjelenésének, elrendezésének és struktúrájának.
    • ViewModel. Hézagként szolgál a View és a Model között, és feldolgozza a kijelző logikáját. Kéri az adatmodellt, és átadja azt a Megtekintés olyan formában, amely könnyen használható. Szintén tartalmaz események feldolgozását, amelyeket az alkalmazás felhasználója készített a Nézetben, például megnyom egy gombot. Ezenkívül a ViewModel felelős a megjelenítendő további megjelenítési állapotok meghatározásáért, például, hogy a letöltés folyamatban van-e.

    Az összetevők közötti kapcsolat és kölcsönhatás a képen látható:

    Az mvvm használatának leállítása

    A nyilak mutatják a függőségeket: A View ismeri a ViewModelt, és a ViewModel ismeri a Modellt, de a modell nem tud semmit a ViewModelről, amely semmit sem tud a nézetről.

    A folyamat a következő: A ViewModel adatokat kér a Modelltől, és szükség esetén frissíti. A Model értesíti a ViewModelt, hogy az adatok ott vannak. A ViewModel átveszi az adatokat, átalakítja, és értesíti a Megtekintést arról, hogy a felhasználói felülethez tartozó adatok készen állnak. A ViewModel és a View közötti kapcsolatot automatikus adatkötés és megjelenítés hajtja végre. A mi esetünkben ez a Databinding könyvtár használatával érhető el. Adatgyűjtéssel a nézet a ViewModel adatai alapján frissül.

    Az automatikus kötés jelenléte (adatbevitel) a minta fő különbsége a PresentationModel mintától és az MVP-től (az MVP Presenterben a Megtekintés a hívás módjain keresztül a mellékelt felületen keresztül változik).

    MVVM az Androidon

    Ezért kezdtem el használni az MVVM-et. De ahogy a programozás gyakran történik, az elmélet és a gyakorlat nem ugyanazok. És a projekt befejezése után elégedetlenséget éreztem. Valami baj van ezzel a megközelítéssel, amit nem tetszett, de nem értettem, mi volt.

    Aztán úgy döntöttem, hogy egy MVVM rendszert rajzolok Androidra:

    Az mvvm használatának leállítása

    Vegyük fontolóra, hogy ennek eredményeképpen kiderül:

    A ViewModel tartalmazza az xml-ben használt mezőket az adat-összerendeléshez (android: text = "@"), kezeli a nézetben hívott eseményeket (android: onClick = "@"). A modellektől adatokat kér, azokat átalakítja, és az adatgyűjtés segítségével ezek az adatok a Nézetbe esnek.

    A töredék egyidejűleg két szerepet tölt be: egy belépési pont, amely inicializálja és kommunikál a rendszerrel, és a View.

    Az a tény, hogy a töredék (vagy tevékenység) az MVP és az MVVM minták megértésében nézetként tekintik, már általános gyakorlatgá vált, ezért nem foglalkozom ezzel.

    A tevékenység megfordulása és a tevékenység újbóli létrehozása érdekében a ViewModel élőben marad, amíg a Nézet újra létrejön (ebben az esetben a Töredék). Ezt a tőr és az egyedi területek segítségével érik el. Nem megyek a részletekbe, már sok jó cikk van a tőrről. Szavaikban a következő történik:

    • A ViewModel egy tőrrel (és annak példányában él) van létrehozva, és a töredék szükség esetén veszi át.
    • Ha egy töredék forgatás közben meghal, az DetachView () nevét a ViewModel-ből hívja.
    • A ViewModel továbbra is él, háttérfolyamatok is, és nagyon kényelmes.
    • Ezután, amikor a töredék újra létrejön, a mountView () függvényt meghívja, és megjeleníti a nézetet (a felület segítségével).
    • Ha a fragmens meghal teljesen, ahelyett, hogy a kanyarban, megöli hatálya (nullázni kívánt komponens tőrt. ViewModel és összegyűjthető, szemétgyűjtő „th együtt a komponens) és ViewModel meghal. Ezt a BaseFragmentben hajtják végre.

    Miért adja át a töredék a ViewModel-hez az MvvmView felület használatával? Erre azért van szükség, hogy a parancsokat kézzel hívhassuk a Nézetre. Nem minden a Databinding könyvtár segítségével végezhető el.

    Ha el szeretné menteni az állapotot abban az esetben, ha a rendszer megöli az alkalmazást, menthetjük és visszaállíthatjuk a ViewModel állapotot a savedInstanceState-fragmenst használva.

    Valami ilyesmi működik.

    A figyelmes olvasó megkérdezi: "Mi a szenvedés a tőrök egyéni körét. ha csak a Fragmentet használhatja konténerként, és hívhatja a setRetainInstance (true) -t. " Igen, ezt megteheti. De egy rajzot rajzoltam, figyelembe vettem, hogy a Tevékenység vagy a ViewGroup mint Nézet használható.

    Nemrégiben jó példát mutatok az MVVM implementációjára. teljesen tükrözve a festett szerkezetet. Kivéve néhány árnyalatot, mindent nagyon jól végzik. Nézd, ha érdekel.

    A dualitás problémája

    Miután rajzoltam a diagramot és mindent átgondoltam, rájöttem, hogy nem örülök ennek a megközelítésnek. Nézd meg újra a diagramot. Lásd a vastag nyilakat "adatbevitel" és "kézi parancsok megtekintéséhez"? Itt van. Most részletesebben elmondom.

    Miután adatgyűjtés történt. a legtöbb adat egyszerűen beállítható a View xml-be (a BindingAdapter létrehozásával, ha szükséges). De vannak olyan esetek, amelyek nem illeszkednek ehhez a megközelítéshez. Ezek közé tartoznak a párbeszédek, a pirítós, az animációk, a késleltetett műveletek és más összetett műveletek a Nézet elemekkel.

    Emlékezzünk egy példát a TextView-ra:

    Mi van, ha ezt a szöveget a view.post (new Runnable ()) paranccsal kell beállítani. (Nem gondoljuk, miért, mi gondoljuk hogyan)

    BindingAdaptort hozhat létre, amelyben létrehozza a "byPost" attribútumot, és figyelembe veszi az elem felsorolt ​​attribútumainak jelenlétét.

    És most minden alkalommal, amikor a TextView mindkét attribútumot megadta, ezt a BindingAdaptort fogja használni. Attribútum hozzáadása xml-hez:

    A ViewModelnek rendelkeznie kell egy olyan tulajdonsággal, amely jelzi, hogy az érték beállításakor a view.post () -t kell használnunk. Adja hozzá:

    Látod mennyire kell mindent tenni egy nagyon egyszerű akció megvalósítása érdekében?

    Ezért sokkal könnyebb ilyen dolgokat közvetlenül megtenni a Nézeten. Vagyis használja az MvvmView interfészt, amelyet a töredékünk hajt végre, és felhívja a View módokat (szintén, ahogy általában az MVP-ben történik).

    Itt jelenik meg a dualitás problémája: a View segítségével két különböző módon dolgozunk. Az egyik az automatikus (az adatállapoton keresztül), a második a kézi (a parancsokon lévő hívásokon keresztül). Személy szerint én nem tetszik.

    Az államok problémája

    Kiderült, hogy meg kell valahogy tartani nemcsak az állam View, ViewModel bemutatott egy sor területen, hanem a gyakorlatok okozó ViewModel a megtekintéshez.

    Ez a probléma megoldható úgy, hogy a ViewModel zászlók mezőket minden különálló esetre beállítja. Nem túl szép és nem univerzális. De működni fog.

    Az államokról

    A probléma az állami adta az ötletet, hogy az állam az objektum rekonstruálni lehet kétféleképpen: egy sor paramétert, amely jellemzi a feltétel, vagy állítsa az intézkedéseket, amelyek szükségesek ahhoz, hogy az elemet a kívánt állapot.

    Képzeljen el egy Rubik kockát. Állapotját 9 színben lehet leírni az egyik oldalon. És lehetséges egy olyan mozdulatot használni, amely az eredeti állapotból a szükségeshez vezet.

    Lehet, hogy csak egy fordulatra van szüksége, és talán több mint kilenc. Kiderül, hogy a helyzettől függően jobb vagy rosszabb az állam leírása (kevesebb adatra van szükség).

    Érvelésem összefüggésében a Moxy egyik jellemzője érdekes - tárolja a nézetállapotot a nézeteket tartalmazó parancsok készleteként. És amikor először tudtam erről, furcsának tűnt számomra.

    De most, miután az összes gondolkodás (amit veled megosztottam), azt hiszem, ez egy nagyon jó döntés.
    mert:

    • Nem mindig lehetséges (kényelmesen) az állapotot csak adatok (mezők) formájában ábrázolni.
    • Az MVP-ben a Viewgal való kommunikáció a hívásokon keresztül történik. Miért nem használja?
    • A valóságban a mezők száma látható. szükséges az állapotának újbóli létrehozásához, sokkal több lehet, mint az általa okozott parancsok száma.

    Ráadásul ez a megközelítés újabb pluszt jelent. Ő, mint a Databinding Library, megoldja a probléma számos különböző államok a maga módján. Szintén nem kell hatalmas kapcsolót írni. az UI megváltoztatása a mezőkészlettől vagy az egyik állapot nevétől függően, mivel a változásokat egy sor hívássorozattal állítja elő.

    És mégsem mondhatok mást Moxy-ről. Kollégáim véleményem szerint és véleményem szerint ma a legjobb könyvtár, amely segít az MVP-mintával való együttműködésben. A kód generálásával minimalizálhatja a fejlesztő erőfeszítéseit. Nem gondolhatsz egy minta végrehajtására, hanem gondolod a projekted működésére. És ez jó.

    De elég az MVP-vel kapcsolatban. Mégis, az MVVM-ről van szó, és itt az idő.

    Szeretem az MVVM mintát, és nem vitatom a profiknak. De legtöbbjük ugyanaz, mint más minták, vagy a fejlesztő ízlése. Igen, és a fő előny még mindig adatbevitel. és nem magának a mintának.

    Az MVVM szimpátiája által rájöttem, hogy a projekt rajta van. Hosszú ideig tanulmányozta a tantárgyat, gondolkodott, vitatkozott és saját magának nyújtott egy sor hátrányt:

    • Az MVVM arra kényszeríti Önt, hogy a View egyidejű használatával két módon működjön: az adatbevitellel és a View módokon keresztül.
    • Az MVVM használatával nem lehet gyönyörűen megoldani az államok problémáját (szükség van arra, hogy mentse a hívást a View metódusra, amikor a nézet megszakadt a ViewModel-ből).
    • Szükség van a Databinding könyvtár fejlettebb használatára, amely időt vesz igénybe a mesterhez.
    • Az xml kód nem minden.

    Igen, megszokja ezeket a hátrányokat. De sok gondolat után arra a következtetésre jutottam, hogy nem akarok olyan mintázattal dolgozni, amely a megközelítések fragmentálódását okozza. És úgy döntöttem, hogy a MVP és a Moxy segítségével írom a következő projektet.

    Használja ezt a mintát - döntsön magára. De én figyelmeztettem.

    PS: Databinding könyvtár

    Talán befejezzük ugyanazt, amit elkezdtünk - a Databinding könyvtárat. Még mindig tetszik. De csak korlátozott mennyiségben fogom használni:

    • Nem kell megkeresnie a findViewById és a setOnClickListener nevet.
    • És hozzon létre kényelmes xml attribútumokat a BindingAdapters használatával (például bind: font = "Roboto.ttf").

    És ez minden. Ez pluszot ad, de nem fog az MVVM-re felhívni.

    Ha a Databinding könyvtárral is dolgozni szeretne, itt néhány hasznos információ:

    Ossza meg ezt