Articles

Android Architecture Patterns Part 2:Model-View-Presenter

Florina Muntenescu
Florina Muntenescu

Follow

Nov 2, 2016 · 6 min read

It’s about time we developers start thinking about how we can apply good architecture patterns in our Android apps. Ennek érdekében a Google Android architektúra tervrajzokat kínál, ahol Erik Hellmannal együtt dolgoztunk az MVP & RxJava mintán. Vessünk egy pillantást arra, hogyan alkalmaztuk, valamint ennek a megközelítésnek az előnyeire és hátrányaira.

itt vannak minden összetevő szerepei:

  • modell — az adatréteg. Felelős az üzleti logika kezeléséért, valamint a hálózati és adatbázis rétegekkel való kommunikációért.
  • nézet-az UI réteg. Megjeleníti az adatokat, és értesíti a műsorvezetőt a felhasználói műveletekről.
  • Presenter-letölti az adatokat a modellből, alkalmazza a felhasználói felület logikáját, kezeli a Nézet állapotát, eldönti, hogy mit jelenítsen meg, és reagál a felhasználói beviteli értesítésekre a nézetből.

mivel a Nézet és a műsorvezető szorosan együttműködnek, hivatkozniuk kell egymásra. Annak érdekében, hogy a Bemutatóegység tesztelhető legyen a JUnit segítségével, a Nézet absztrahálódik, és egy interfész használható. Az előadó és a hozzá tartozó nézet közötti összefüggést a Contract interfész osztály határozza meg, így a kód olvashatóbb és a kettő közötti kapcsolat könnyebben érthető.

Model-View-Műsorvezető osztály felépítése

A Modell-Nézet-Műsorvezető Minta & RxJava az Android Építészeti Tervrajzok

A tervrajz, minta egy alkalmazás. Lehetővé teszi a felhasználó számára, hogy hozzon létre, olvassa el, frissítse és törölje a “csinálni” feladatokat, valamint szűrőket alkalmazzon a megjelenített feladatok listájára. RxJava használják, hogy mozog le a fő szál, valamint képes kezelni aszinkron műveleteket.

Model

a modell a távoli és helyi adatforrásokkal együtt működik az adatok beszerzéséhez és mentéséhez. Itt kezelik az üzleti logikát. Például, ha a Tasks listát kéri, a modell megpróbálja letölteni őket a helyi adatforrásból. Ha üres, lekérdezi a hálózatot, elmenti a választ a helyi adatforrásba, majd visszaadja a listát.

a feladatok visszakeresése RxJava segítségével történik:

public Observable<List<Task>> getTasks(){ 
...
}

a modell paramétereket kap a helyi és távoli adatforrások konstruktor interfészeiben, így a modell teljesen független minden Android osztálytól, így könnyen egység tesztelhető a JUnit segítségével. Például annak tesztelésére, hogy agetTasks adatokat kér a helyi forrásból, a következő tesztet hajtottuk végre:

@Mock 
private TasksDataSource mTasksRemoteDataSource;
@Mock
private TasksDataSource mTasksLocalDataSource;
...
@Test
public void getTasks_requestsAllTasksFromLocalDataSource() {
// Given that the local data source has data available
setTasksAvailable(mTasksLocalDataSource, TASKS);
// And the remote data source does not have any data available
setTasksNotAvailable(mTasksRemoteDataSource);
// When tasks are requested from the tasks repository
TestSubscriber<List<Task>> testSubscriber =
new TestSubscriber<>();
mTasksRepository.getTasks().subscribe(testSubscriber); // Then tasks are loaded from the local data source
verify(mTasksLocalDataSource).getTasks();
testSubscriber.assertValue(TASKS);
}

nézet

a nézet az előadóval együtt működik az adatok megjelenítéséhez, és értesíti a műsorvezetőt a felhasználó tevékenységéről. Az MVP tevékenységekben a töredékek és az egyedi Android nézetek megtekinthetők. A mi választásunk a töredékek használata volt.

minden nézet ugyanazt a BaseView felületet valósítja meg, amely lehetővé teszi a műsorvezető beállítását.

public interface BaseView<T> {
void setPresenter(T presenter);
}

a Nézet értesíti a műsorvezetőt, hogy készen áll a Frissítésre a A műsorvezető módszere a onResume. A Nézet felhívja presenter.unsubscribe()in onPause hogy elmondja a műsorvezetőnek, hogy már nem érdekli a frissítés. Ha a Nézet megvalósítása androidos egyéni nézet, akkor asubscribe ésunsubscribe módszereketonAttachedToWindow ésonDetachedFromWindow – ra kell hívni. A felhasználói műveletek, mint például a gombkattintások, megfelelő módszereket váltanak ki az előadóban, ez az, amely eldönti, hogy mi történjen ezután.

a nézeteket eszpresszóval tesztelik. A statisztikai képernyőnek például meg kell jelenítenie az aktív és befejezett feladatok számát. A teszt, amely ellenőrzi, hogy ez helyesen történik-e, először néhány feladatot a TaskRepository – ba helyez; ezután elindítja a StatisticsActivity és ellenőrzi a nézetek tartalmát:

@Before 
public void setup() {
// Given some tasks
TasksRepository.destroyInstance();
TasksRepository repository = Injection.provideTasksRepository( InstrumentationRegistry.getContext()); repository.saveTask(new Task("Title1", "", false));
repository.saveTask(new Task("Title2", "", true)); // Lazily start the Activity from the ActivityTestRule
Intent startIntent = new Intent();
mStatisticsActivityTestRule.launchActivity(startIntent);
}@Test
public void Tasks_ShowsNonEmptyMessage() throws Exception {
// Check that the active and completed tasks text is displayed
Context context = InstrumentationRegistry.getTargetContext();
String expectedActiveTaskText = context
.getString(R.string.statistics_active_tasks);
String expectedCompletedTaskText = context
.getString(R.string.statistics_completed_tasks); onView(withText(containsString(expectedActiveTaskText)))
.check(matches(isDisplayed()));
onView(withText(containsString(expectedCompletedTaskText)))
.check(matches(isDisplayed()));
}

Presenter

a műsorvezető és annak megfelelő nézetét a tevékenység hozza létre. A nézetre és a TaskRepository – A modell – hivatkozásokat a műsorvezető konstruktorának adják. A kivitelező végrehajtásakor a műsorvezető a Nézet setPresenter módszerét hívja. Ez egyszerűsíthető egy függőségi befecskendező keretrendszer használatakor, amely lehetővé teszi az Előadók befecskendezését a megfelelő nézetekben, csökkentve az osztályok összekapcsolását. A tőrrel ellátott ToDo-MVP végrehajtását egy másik minta fedezi.

minden előadó ugyanazt a BasePresenter felületet valósítja meg.

public interface BasePresenter {
void subscribe();
void unsubscribe();
}

amikor a subscribe metódust hívják, a műsorvezető elkezdi kérni az adatokat a modelltől, majd a felhasználói felület logikáját alkalmazza a kapott adatokra, és beállítja a nézetre. Például a StatisticsPresenter – ban minden feladatot a TaskRepository – tól kérnek-ezután a beolvasott feladatokat az aktív és befejezett feladatok számának kiszámításához használják. Ezeket a számokat a Nézet showStatistics(int numberOfActiveTasks, int numberOfCompletedTasks) metódusának paramétereként használjuk.

egy egység teszt annak ellenőrzésére, hogy valóban a showStatistics módszert hívják a megfelelő értékeket könnyen megvalósítható. A TaskRepository és a StatisticsContract.View és paraméterként adjuk meg a kigúnyolt objektumokat aStatisticsPresenter objektum konstruktorának. A teszt végrehajtása:

@Test 
public void loadNonEmptyTasksFromRepository_CallViewToDisplay() {
// Given an initialized StatisticsPresenter with
// 1 active and 2 completed tasks
setTasksAvailable(TASKS); // When loading of Tasks is requested
mStatisticsPresenter.subscribe(); // Then the correct data is passed on to the view
verify(mStatisticsView).showStatistics(1, 2);
}

a unsubscribe módszer szerepe az előadó összes előfizetésének törlése, ezáltal elkerülve a memória szivárgását.

asubscribe ésunsubscribe mellett minden előadó más módszereket is bemutat, amelyek megfelelnek a nézet felhasználói műveleteinek. Például a AddEditTaskPresenter, olyan módszereket ad hozzá, mint például a createTask, amelyeket akkor hívnak, ha a felhasználó megnyomja az új feladatot létrehozó gombot. Ez biztosítja, hogy az összes felhasználói művelet – következésképpen az összes felhasználói felület logikája – átmegy a bemutatón, ezáltal egység tesztelhető.

A Model-View-Presenter Minta hátrányai

A Model-View-Presenter minta nagyon jól elkülöníti az aggodalmakat. Bár ez biztos, hogy egy profi, amikor egy kis alkalmazást vagy prototípust fejleszt, ez úgy tűnik, mint egy felső. A használt interfészek számának csökkentése érdekében egyes fejlesztők eltávolítják aContract interfész osztályt, valamint az előadó felületét.

az MVP egyik buktatója akkor jelenik meg, amikor a felhasználói felület logikáját áthelyezi az előadóra: ez most egy mindent tudó osztály lesz, több ezer sornyi kóddal. Ennek megoldásához ossza meg még jobban a kódot, és ne felejtsen el olyan osztályokat létrehozni, amelyek csak egy felelősséggel rendelkeznek, és egységesen tesztelhetők.

következtetés

a modell-nézet-vezérlő mintának két fő hátránya van: először is, a nézetnek mind a vezérlőre, mind a modellre van hivatkozása; másodszor, nem korlátozza az UI logika kezelését egyetlen osztályra, ezt a felelősséget megosztják a vezérlő és a nézet vagy a modell között. A Model-View-Presenter minta mindkét problémát úgy oldja meg, hogy megszakítja a nézetet a modellel, és csak egy osztályt hoz létre, amely kezeli a Nézet bemutatásával kapcsolatos összes dolgot — a bemutatót: egyetlen osztályt, amelyet könnyű egység tesztelni.

mi van, ha egy esemény alapú architektúrát akarunk, ahol a Nézet reagál a változásokra? Maradjon hangolva az Android architektúra Tervrajzaiban mintavételezett következő mintákra, hogy megnézze, hogyan valósítható meg ez. Addig olvassa el a modell-nézet-ViewModel minta végrehajtását a upday alkalmazásban.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük