117
@FMuntenescu A Journey Through MV Wonderland

A Journey Through MV Wonderland

Embed Size (px)

Citation preview

@FMuntenescu

A Journey Through MVWonderland

@FMuntenescu

Robust, stable, testable, modular, easy to extend

@FMuntenescu

MV ( C P VM )

@FMuntenescu

MV ( C P VM )

Model

@FMuntenescu

MV ( C P VM )

View

Model

@FMuntenescu

MV ( C P VM )

View

Model

@FMuntenescu

MV ( C P VM )

View

Model

@FMuntenescu

Model – View – Controller

@FMuntenescu

Controller

Model

View1…1

@FMuntenescu

Controller

Model

View

Userinput

@FMuntenescu

UpdateModel

Controller

Model

View

Userinput

@FMuntenescu

Update

UpdateModel

Controller

Model

View

Userinput

@FMuntenescu

Querylatestdata

Update

UpdateModel

Controller

Model

View

Userinput

@FMuntenescu

Model – View – Controllerin Android

@FMuntenescu

Activity

Controller

Model

View1…1

@FMuntenescu

Controller

Model

View1…1

@FMuntenescu

Controller

Model

View

Userinput

@FMuntenescu

Informaboutinput

Controller

Model

View

Userinput

@FMuntenescu

UpdateModel

Informaboutinput

Controller

Model

View

Userinput

@FMuntenescu

Update

UpdateModel

Informaboutinput

Controller

Model

View

Userinput

@FMuntenescu

Querylatestdata

Update

UpdateModel

Informaboutinput

Controller

Model

View

Userinput

@FMuntenescu

IView

Controller

Model

View1…1

@FMuntenescu

Who handles UI logic?

@FMuntenescu

class User {String firstName;String lastName;…

}

@FMuntenescu

class User {String firstName;String lastName;…

}

displayName = lastName + “, “ + firstName

@FMuntenescu

class User {String firstName; JaneString lastName; Doe…

}

displayName = Doe, JanelastName + “, “ + firstName

@FMuntenescu

View?User user = userModel.getUser();

nameTextView.setText(user.getLastName() + ", " + user.getFirstName())

@FMuntenescu

Model?

String name = userModel.getDisplayName();

nameTextView.setText(name);

@FMuntenescu

The View knows too much!

@FMuntenescu

IView

Controller

Model

View1…1

@FMuntenescu

IView

Controller

Model

View1…1

@FMuntenescu

Controller ModelView1…1

IView

@FMuntenescu

Presenter ModelView1…1

IView

@FMuntenescu

Model – View – Presenter

@FMuntenescu

Presenter ModelView1…1

IView IPresenter

@FMuntenescu

Contract

Presenter ModelView1…1

IView IPresenter

@FMuntenescu

interface IView {void setName(String name);

}

@FMuntenescu

IUserModel userModel;

IView view;

Presenter(IUserModel userModel,IView view) {

this.userModel = userModel;this.view = view;

}

@FMuntenescu

IUserModel userModel;

IView view;

Presenter(IUserModel userModel,IView view) {

this.userModel = userModel;this.view = view;

}

@FMuntenescu

interface IPresenter {void onLoad();

}

@FMuntenescu

@Overridepublic void onLoad() {

User user = userModel.getUser();String displayName =

user.getFirstName()+ ", " + user.getLastName();

view.setName(displayName);}

@FMuntenescu

@Overridepublic void onLoad() {

User user = userModel.getUser();String displayName =

user.getFirstName()+ ", " + user.getLastName();

view.setName(displayName);}

@FMuntenescu

@Overridepublic void onLoad() {

User user = userModel.getUser();String displayName =

user.getFirstName()+ ", " + user.getLastName();

view.setName(displayName);}

@FMuntenescu

@MockIUserModel userModel;

@MockIView view;

Presenter presenter;

@Beforepublic void setup() {

…presenter =

new Presenter(userModel, view);}

@FMuntenescu

@MockIUserModel userModel;

@MockIView view;

Presenter presenter;

@Beforepublic void setup() {

…presenter =

new Presenter(userModel, view);}

@FMuntenescu

@Testpublic void displayName_setOnLoad() {when(userModel.getUser())

.thenReturn(new User(“Jane”, “Doe”);

presenter.onLoad();

verify(view).setName(“Doe, Jane”);}

@FMuntenescu

@Testpublic void displayName_setOnLoad() {when(userModel.getUser())

.thenReturn(new User(“Jane”, “Doe”);

presenter.onLoad();

verify(view).setName(“Doe, Jane”);}

@FMuntenescu

@Testpublic void displayName_setOnLoad() {when(userModel.getUser())

.thenReturn(new User(“Jane”, “Doe”);

presenter.onLoad();

verify(view).setName(“Doe, Jane”);}

@FMuntenescu

@Testpublic void displayName_setOnLoad() {when(userModel.getUser())

.thenReturn(new User(“Jane”, “Doe”);

presenter.onLoad();

verify(view).setName(“Doe, Jane”);}

@FMuntenescu

Presenter ModelView1…1

IView IPresenter

@FMuntenescu

IUserModel userModel;IView view;Presenter(IUserModel userModel, IView view) {

this.userModel = userModel;this.view = view;

}

void onLoad() {…

view.setName(displayName);}

@FMuntenescu

IUserModel userModel;IView view;Presenter(IUserModel userModel, IView view) {

this.userModel = userModel;this.view = view;

}

void onLoad() {…

view.setName(displayName);}

Observable<String> getName() {…

}

@FMuntenescu

class View {

…viewModel.getName()

.subscribe(name-> setName(name));

…private void setName(String name){

nameTextView.setText(name);

}

@FMuntenescu

IUserModel userModel;IView view;

Presenter(IUserModel userModel, IView view) {

userModel = userModel;view = view;

}

@FMuntenescu

interface IView {void setName(String name);

}

@FMuntenescu

Presenter ModelView1…*

IView IPresenter

@FMuntenescu

ViewModel ModelView1…*

@FMuntenescu

Model – View – ViewModel

@FMuntenescu

ViewModel ModelView1…*

@FMuntenescu

class User {String firstName;String lastName;

Date dateOfBirth;}

@FMuntenescu

class User {String firstName; JaneString lastName; Doe

Date dateOfBirth; 04.04.1987}

@FMuntenescu

class User {String firstName; JaneString lastName; Doe

Date dateOfBirth; 04.04.1987}

Name: Doe, JaneAge: 29

@FMuntenescu

class ViewModel {

Observable<String> getName() {… }

Observable<Integer> getAge() {… }

}

@FMuntenescu

class ViewModel {

Observable<DisplayableUser> getUser() {…

}}

@FMuntenescu

class DisplayableUser {String mName;int mAge;

}

class ViewModel {

Observable<DisplayableUser> getUser() {…

}}

@FMuntenescu

@MockIUserModel userModel;

ViewModel viewModel;

@Beforevoid setup() {

…viewModel = new ViewModel(userModel);

}

@FMuntenescu

@MockIUserModel userModel;

ViewModel viewModel;

@Beforepublic void setup() {

…viewModel = new ViewModel(userModel);

}

@FMuntenescu

@Testpublic void getUser_emitsCorrectValue() {when(userModel.getUser())

.thenReturn(new User(“Jane”,”Doe”, new Date(4,4,1987));

viewModel.getUser().subscribe(testSubscriber);

testSubscriber.assertValue(expectedUser);}

@FMuntenescu

@Testpublic void getUser_emitsCorrectValue() {when(userModel.getUser())

.thenReturn(new User(“Jane”,”Doe”, new Date(4,4,1987));

viewModel.getUser().subscribe(testSubscriber);

testSubscriber.assertValue(expectedUser);}

@FMuntenescu

@Testpublic void getUser_emitsCorrectValue() {when(userModel.getUser())

.thenReturn(new User(“Jane”,”Doe”, new Date(4,4,1987));

viewModel.getUser().subscribe(testSubscriber);

testSubscriber.assertValue(expectedUser);}

@FMuntenescu

@Testpublic void getUser_emitsCorrectValue() {when(userModel.getUser())

.thenReturn(new User(“Jane”,”Doe”, new Date(4,4,1987));

viewModel.getUser().subscribe(testSubscriber);

testSubscriber.assertValue(expectedUser);}

@FMuntenescu

Model – View – Presenter &

Model – View – ViewModel

@FMuntenescu

class Presenter {void onLoad() {

…view.setName(displayName);

}}

class ViewModel {Observable<String> getName() {

…}

}

@FMuntenescu

Who is the View?

@FMuntenescu

(P|VM)Activity

@FMuntenescu

(P|VM)Fragment

Activity

@FMuntenescu

(P|VM)Fragment

Activity

CustomView

CustomView

@FMuntenescu

class View implements IView {

@InjectPresenter presenter;

presenter.onLoad(this);

@FMuntenescu

class View {

@InjectViewModel viewModel;

@FMuntenescu

Fragment

SomeView

AnotherView

@FMuntenescu

<RelativeLayout><my.custom.SomeView /><my.custom.AnotherView />

</RelativeLayout>

Fragment

SomeView

AnotherView

@FMuntenescu

<RelativeLayout><my.custom.SomeView /><my.custom.AnotherView />

</RelativeLayout>

Fragment

SomeView

AnotherView

NewView

@FMuntenescu

<RelativeLayout><my.custom.SomeView /><my.custom.NewView /><my.custom.AnotherView />

</RelativeLayout>

Fragment

AnotherView

NewView

@FMuntenescu

How to split Views?

@FMuntenescu

ComplexityResponsibility

Reusability

@FMuntenescu

What goes where?V ? ( P VM )

@FMuntenescu

Does it contain UI logic?

View( P | VM )

Yes No

@FMuntenescu

(P| VM) ModelView

@FMuntenescu

(P| VM) ModelView

@FMuntenescu

How to handle dependencies between

Views?

@FMuntenescu

Fragment

View1

View2

@FMuntenescu

Fragment

View1

View2

View1

View2

@FMuntenescu

JaneFragment

View1

View2

Doe

4.4.1987

CONTINUE

@FMuntenescu

Fragment

View1

View2

Model

@FMuntenescu

Fragment Presenter

View1 Presenter

View2 Presenter

@FMuntenescu

Fragment ViewModel

View1 ViewModel

View2 ViewModel

@FMuntenescu

How to handle Android lifecycle?

@FMuntenescu

onResume /onPause

@FMuntenescu

@Overrideprotected void onResume() {

…presenter.onLoad();

}

@Overrideprotected void onPause() {

presenter.onStopLoad();…

}

@FMuntenescu

@Overrideprotected void onResume() {

…presenter.onLoad();

}

@Overrideprotected void onPause() {

presenter.onStopLoad();…

}

@FMuntenescu

@Overrideprotected void onResume() {

…viewModel.getDataStream()

.subscribe(…);}

@Overrideprotected void onPause() {

// unsubscribe…

}

@FMuntenescu

@Overrideprotected void onResume() {

…viewModel.getDataStream()

.subscribe(…);}

@Overrideprotected void onPause() {

// unsubscribe…

}

@FMuntenescu

onAttachedToWindow /onDetachedFromWindow

@FMuntenescu

@Overridevoid onAttachedToWindow() {

presenter.onLoad();…

}

@Overridevoid onDetachedFromWindow() {

…presenter.onStopLoad();

}

@FMuntenescu

@Overridevoid onAttachedToWindow() {

presenter.onLoad();…

}

@Overridevoid onDetachedFromWindow() {

…presenter.onStopLoad();

}

@FMuntenescu

@Overridevoid onAttachedToWindow() {

viewModel.getDataStream().subscribe(…);

…}

@Overridevoid onDetachedFromWindow() {

…// unsubscribe

}

@FMuntenescu

@Overridevoid onAttachedToWindow() {

viewModel.getDataStream().subscribe(…);

…}

@Overridevoid onDetachedFromWindow() {

…// unsubscribe

}

@FMuntenescu

onSaveInstanceState /onRestoreInstanceState

@FMuntenescu

@Overridevoid onSaveInstanceState(Bundle state) {

state.putAll(presenter/viewModel.getState());

}

@Overridevoid onRestoreInstanceState(Bundle state) {

presenter/viewModel.restoreState(state);

}

@FMuntenescu

@Overridevoid onSaveInstanceState(Bundle state) {

state.putAll(presenter/viewModel.getState());

}

@Overridevoid onRestoreInstanceState(Bundle state) {

presenter/viewModel.restoreState(state);

}

@FMuntenescu

@OverrideParcelable onSaveInstanceState() {

// save state}

@Overridevoid onRestoreInstanceState(

Parcelable state) {// restore state

}

@FMuntenescu

MVC vs MVP vs MVVM

@FMuntenescu

Are your Android classes logic free?

@FMuntenescu

Can you unit test everything?

@FMuntenescu

Do your classes do one thing and one thing only?

@FMuntenescu

Robust, stable, testable, modular, easy to extend

@FMuntenescu

A Journey Through MVWonderland

[email protected]

GoogleArchitectureBlueprintshttps://github.com/googlesamples/android-architecture

MVPvsMVVMexamplehttps://github.com/florina-muntenescu/MVPvsMVVM

https://upday.github.io/