Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
@FMuntenescu
A Journey Through MV
Wonderland
@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
View
1	…	1
@FMuntenescu
Controller
Model
View
User	input
@FMuntenescu
Update	Model
Controller
Model
View
User	input
@FMuntenescu
Update
Update	Model
Controller
Model
View
User	input
@FMuntenescu
Query	latest	data
Update
Update	Model
Controller
Model
View
User	input
@FMuntenescu
Model – View – Controller
in Android
@FMuntenescu
Activity
Controller
Model
View
1	…	1
@FMuntenescu
Controller
Model
View
1	…	1
@FMuntenescu
Controller
Model
View
User	input
@FMuntenescu
Inform	about	input
Controller
Model
View
User	input
@FMuntenescu
Update	Model
Inform	about	input
Controller
Model
View
User	input
@FMuntenescu
Update
Update	Model
Inform	about	input
Controller
Model
View
User	input
@FMuntenescu
Query	latest	data
Update
Update	Model
Inform	about	input
Controller
Model
View
User	input
@FMuntenescu
IView
Controller
Model
View
1	…	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; Jane
String lastName; Doe
…
}
displayName = Doe, Jane
lastName + “, “ + firstN...
@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
View
1	…	1
@FMuntenescu
IView
Controller
Model
View
1	…	1
@FMuntenescu
Controller ModelView
1	…	1
IView
@FMuntenescu
Presenter ModelView
1	…	1
IView
@FMuntenescu
Model – View – Presenter
@FMuntenescu
Presenter ModelView
1	…	1
IView IPresenter
@FMuntenescu
Contract
Presenter ModelView
1	…	1
IView IPresenter
@FMuntenescu
interface IView {
void setName(String name);
}
@FMuntenescu
IUserModel userModel;
IView view;
Presenter(IUserModel userModel,
IView view) {
this.userModel = userModel;
t...
@FMuntenescu
IUserModel userModel;
IView view;
Presenter(IUserModel userModel,
IView view) {
this.userModel = userModel;
t...
@FMuntenescu
interface IPresenter {
void onLoad();
}
@FMuntenescu
@Override
public void onLoad() {
User user = userModel.getUser();
String displayName =
user.getFirstName()
+ ...
@FMuntenescu
@Override
public void onLoad() {
User user = userModel.getUser();
String displayName =
user.getFirstName()
+ ...
@FMuntenescu
@Override
public void onLoad() {
User user = userModel.getUser();
String displayName =
user.getFirstName()
+ ...
@FMuntenescu
@Mock
IUserModel userModel;
@Mock
IView view;
Presenter presenter;
@Before
public void setup() {
…
presenter ...
@FMuntenescu
@Mock
IUserModel userModel;
@Mock
IView view;
Presenter presenter;
@Before
public void setup() {
…
presenter ...
@FMuntenescu
@Test
public void displayName_setOnLoad() {
when(userModel.getUser())
.thenReturn(new User(“Jane”, “Doe”);
pr...
@FMuntenescu
@Test
public void displayName_setOnLoad() {
when(userModel.getUser())
.thenReturn(new User(“Jane”, “Doe”);
pr...
@FMuntenescu
@Test
public void displayName_setOnLoad() {
when(userModel.getUser())
.thenReturn(new User(“Jane”, “Doe”);
pr...
@FMuntenescu
@Test
public void displayName_setOnLoad() {
when(userModel.getUser())
.thenReturn(new User(“Jane”, “Doe”);
pr...
@FMuntenescu
Presenter ModelView
1	…	1
IView IPresenter
@FMuntenescu
IUserModel userModel;
IView view;
Presenter(IUserModel userModel, IView view) {
this.userModel = userModel;
t...
@FMuntenescu
IUserModel userModel;
IView view;
Presenter(IUserModel userModel, IView view) {
this.userModel = userModel;
t...
@FMuntenescu
class View {
…
viewModel.getName()
.subscribe(name-> setName(name));
…
private void setName(String name){
nam...
@FMuntenescu
IUserModel userModel;
IView view;
Presenter(IUserModel userModel,
IView view) {
userModel = userModel;
view =...
@FMuntenescu
interface IView {
void setName(String name);
}
@FMuntenescu
Presenter ModelView
1	…	*
IView IPresenter
@FMuntenescu
ViewModel ModelView
1	…	*
@FMuntenescu
Model – View – ViewModel
@FMuntenescu
ViewModel ModelView
1	…	*
@FMuntenescu
class User {
String firstName;
String lastName;
Date dateOfBirth;
}
@FMuntenescu
class User {
String firstName; Jane
String lastName; Doe
Date dateOfBirth; 04.04.1987
}
@FMuntenescu
class User {
String firstName; Jane
String lastName; Doe
Date dateOfBirth; 04.04.1987
}
Name: Doe, Jane
Age: ...
@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
@Mock
IUserModel userModel;
ViewModel viewModel;
@Before
void setup() {
…
viewModel = new ViewModel(userModel...
@FMuntenescu
@Mock
IUserModel userModel;
ViewModel viewModel;
@Before
public void setup() {
…
viewModel = new ViewModel(us...
@FMuntenescu
@Test
public void getUser_emitsCorrectValue() {
when(userModel.getUser())
.thenReturn(new User(“Jane”,”Doe”,
...
@FMuntenescu
@Test
public void getUser_emitsCorrectValue() {
when(userModel.getUser())
.thenReturn(new User(“Jane”,”Doe”,
...
@FMuntenescu
@Test
public void getUser_emitsCorrectValue() {
when(userModel.getUser())
.thenReturn(new User(“Jane”,”Doe”,
...
@FMuntenescu
@Test
public void getUser_emitsCorrectValue() {
when(userModel.getUser())
.thenReturn(new User(“Jane”,”Doe”,
...
@FMuntenescu
Model – View – Presenter
&
Model – View – ViewModel
@FMuntenescu
class Presenter {
void onLoad() {
…
view.setName(displayName);
}
}
class ViewModel {
Observable<String> getNa...
@FMuntenescu
Who is the View?
@FMuntenescu
(	P	|	VM	)Activity
@FMuntenescu
(	P	|	VM	)
Fragment
Activity
@FMuntenescu
(	P	|	VM	)
Fragment
Activity
Custom	View
Custom	View
@FMuntenescu
class View implements IView {
@Inject
Presenter presenter;
…
presenter.onLoad(this);
@FMuntenescu
class View {
@Inject
ViewModel viewModel;
@FMuntenescu
Fragment
SomeView
AnotherView
@FMuntenescu
<RelativeLayout>
<my.custom.SomeView />
<my.custom.AnotherView />
</RelativeLayout>
Fragment
SomeView
Another...
@FMuntenescu
<RelativeLayout>
<my.custom.SomeView />
<my.custom.AnotherView />
</RelativeLayout>
Fragment
SomeView
Another...
@FMuntenescu
<RelativeLayout>
<my.custom.SomeView />
<my.custom.NewView />
<my.custom.AnotherView />
</RelativeLayout>
Fra...
@FMuntenescu
How to split Views?
@FMuntenescu
Complexity
Responsibility
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
View	1
View	2
@FMuntenescu
Fragment
View	1
View	2
View	1
View	2
@FMuntenescu
JaneFragment
View	1
View	2
Doe
4.4.1987
CONTINUE
@FMuntenescu
Fragment
View	1
View	2
Model
@FMuntenescu
Fragment Presenter
View	1 Presenter
View	2 Presenter
@FMuntenescu
Fragment ViewModel
View	1 ViewModel
View	2 ViewModel
@FMuntenescu
How to handle Android
lifecycle?
@FMuntenescu
onResume /
onPause
@FMuntenescu
@Override
protected void onResume() {
…
presenter.onLoad();
}
@Override
protected void onPause() {
presenter....
@FMuntenescu
@Override
protected void onResume() {
…
presenter.onLoad();
}
@Override
protected void onPause() {
presenter....
@FMuntenescu
@Override
protected void onResume() {
…
viewModel.getDataStream()
.subscribe(…);
}
@Override
protected void o...
@FMuntenescu
@Override
protected void onResume() {
…
viewModel.getDataStream()
.subscribe(…);
}
@Override
protected void o...
@FMuntenescu
onAttachedToWindow /
onDetachedFromWindow
@FMuntenescu
@Override
void onAttachedToWindow() {
presenter.onLoad();
…
}
@Override
void onDetachedFromWindow() {
…
prese...
@FMuntenescu
@Override
void onAttachedToWindow() {
presenter.onLoad();
…
}
@Override
void onDetachedFromWindow() {
…
prese...
@FMuntenescu
@Override
void onAttachedToWindow() {
viewModel.getDataStream()
.subscribe(…);
…
}
@Override
void onDetachedF...
@FMuntenescu
@Override
void onAttachedToWindow() {
viewModel.getDataStream()
.subscribe(…);
…
}
@Override
void onDetachedF...
@FMuntenescu
onSaveInstanceState /
onRestoreInstanceState
@FMuntenescu
@Override
void onSaveInstanceState(Bundle state) {
state.putAll(
presenter/viewModel.getState());
}
@Override...
@FMuntenescu
@Override
void onSaveInstanceState(Bundle state) {
state.putAll(
presenter/viewModel.getState());
}
@Override...
@FMuntenescu
@Override
Parcelable onSaveInstanceState() {
// save state
}
@Override
void onRestoreInstanceState(
Parcelabl...
@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 MV
Wonderland
jobs@upday.com
Google	Architecture	Blueprints	
https://github.com/googlesampl...
Upcoming SlideShare
Loading in …5
×

A Journey Through MV Wonderland

4,615 views

Published on

Developing an app with a design that changes every few months means that the architecture chosen for the UI has to facilitate change. How do you react fast to UI changes, with minimum amount of code? What pattern is the best for testability? Which pattern gives you most decoupling of classes? MVC, MVP and MVVM are the most popular architecture patterns for implementing user interfaces. Join me on a journey to discover the advantages and disadvantages associated with of each of these and find the best one. We will perform a deep dive into the implementations and tests for each pattern. Learn about the pitfalls that you can expect and how you can avoid them, based on some of the lessons that we have learned.

Published in: Software

A Journey Through MV Wonderland

  1. 1. @FMuntenescu A Journey Through MV Wonderland
  2. 2. @FMuntenescu Robust, stable, testable, modular, easy to extend
  3. 3. @FMuntenescu MV ( C P VM )
  4. 4. @FMuntenescu MV ( C P VM ) Model
  5. 5. @FMuntenescu MV ( C P VM ) View Model
  6. 6. @FMuntenescu MV ( C P VM ) View Model
  7. 7. @FMuntenescu MV ( C P VM ) View Model
  8. 8. @FMuntenescu Model – View – Controller
  9. 9. @FMuntenescu Controller Model View 1 … 1
  10. 10. @FMuntenescu Controller Model View User input
  11. 11. @FMuntenescu Update Model Controller Model View User input
  12. 12. @FMuntenescu Update Update Model Controller Model View User input
  13. 13. @FMuntenescu Query latest data Update Update Model Controller Model View User input
  14. 14. @FMuntenescu Model – View – Controller in Android
  15. 15. @FMuntenescu Activity Controller Model View 1 … 1
  16. 16. @FMuntenescu Controller Model View 1 … 1
  17. 17. @FMuntenescu Controller Model View User input
  18. 18. @FMuntenescu Inform about input Controller Model View User input
  19. 19. @FMuntenescu Update Model Inform about input Controller Model View User input
  20. 20. @FMuntenescu Update Update Model Inform about input Controller Model View User input
  21. 21. @FMuntenescu Query latest data Update Update Model Inform about input Controller Model View User input
  22. 22. @FMuntenescu IView Controller Model View 1 … 1
  23. 23. @FMuntenescu Who handles UI logic?
  24. 24. @FMuntenescu class User { String firstName; String lastName; … }
  25. 25. @FMuntenescu class User { String firstName; String lastName; … } displayName = lastName + “, “ + firstName
  26. 26. @FMuntenescu class User { String firstName; Jane String lastName; Doe … } displayName = Doe, Jane lastName + “, “ + firstName
  27. 27. @FMuntenescu View? User user = userModel.getUser(); nameTextView.setText( user.getLastName() + ", " + user.getFirstName())
  28. 28. @FMuntenescu Model? String name = userModel.getDisplayName(); nameTextView.setText(name);
  29. 29. @FMuntenescu The View knows too much!
  30. 30. @FMuntenescu IView Controller Model View 1 … 1
  31. 31. @FMuntenescu IView Controller Model View 1 … 1
  32. 32. @FMuntenescu Controller ModelView 1 … 1 IView
  33. 33. @FMuntenescu Presenter ModelView 1 … 1 IView
  34. 34. @FMuntenescu Model – View – Presenter
  35. 35. @FMuntenescu Presenter ModelView 1 … 1 IView IPresenter
  36. 36. @FMuntenescu Contract Presenter ModelView 1 … 1 IView IPresenter
  37. 37. @FMuntenescu interface IView { void setName(String name); }
  38. 38. @FMuntenescu IUserModel userModel; IView view; Presenter(IUserModel userModel, IView view) { this.userModel = userModel; this.view = view; }
  39. 39. @FMuntenescu IUserModel userModel; IView view; Presenter(IUserModel userModel, IView view) { this.userModel = userModel; this.view = view; }
  40. 40. @FMuntenescu interface IPresenter { void onLoad(); }
  41. 41. @FMuntenescu @Override public void onLoad() { User user = userModel.getUser(); String displayName = user.getFirstName() + ", " + user.getLastName(); view.setName(displayName); }
  42. 42. @FMuntenescu @Override public void onLoad() { User user = userModel.getUser(); String displayName = user.getFirstName() + ", " + user.getLastName(); view.setName(displayName); }
  43. 43. @FMuntenescu @Override public void onLoad() { User user = userModel.getUser(); String displayName = user.getFirstName() + ", " + user.getLastName(); view.setName(displayName); }
  44. 44. @FMuntenescu @Mock IUserModel userModel; @Mock IView view; Presenter presenter; @Before public void setup() { … presenter = new Presenter(userModel, view); }
  45. 45. @FMuntenescu @Mock IUserModel userModel; @Mock IView view; Presenter presenter; @Before public void setup() { … presenter = new Presenter(userModel, view); }
  46. 46. @FMuntenescu @Test public void displayName_setOnLoad() { when(userModel.getUser()) .thenReturn(new User(“Jane”, “Doe”); presenter.onLoad(); verify(view).setName(“Doe, Jane”); }
  47. 47. @FMuntenescu @Test public void displayName_setOnLoad() { when(userModel.getUser()) .thenReturn(new User(“Jane”, “Doe”); presenter.onLoad(); verify(view).setName(“Doe, Jane”); }
  48. 48. @FMuntenescu @Test public void displayName_setOnLoad() { when(userModel.getUser()) .thenReturn(new User(“Jane”, “Doe”); presenter.onLoad(); verify(view).setName(“Doe, Jane”); }
  49. 49. @FMuntenescu @Test public void displayName_setOnLoad() { when(userModel.getUser()) .thenReturn(new User(“Jane”, “Doe”); presenter.onLoad(); verify(view).setName(“Doe, Jane”); }
  50. 50. @FMuntenescu Presenter ModelView 1 … 1 IView IPresenter
  51. 51. @FMuntenescu IUserModel userModel; IView view; Presenter(IUserModel userModel, IView view) { this.userModel = userModel; this.view = view; } void onLoad() { … view.setName(displayName); }
  52. 52. @FMuntenescu IUserModel userModel; IView view; Presenter(IUserModel userModel, IView view) { this.userModel = userModel; this.view = view; } void onLoad() { … view.setName(displayName); } Observable<String> getName() { … }
  53. 53. @FMuntenescu class View { … viewModel.getName() .subscribe(name-> setName(name)); … private void setName(String name){ nameTextView.setText(name); }
  54. 54. @FMuntenescu IUserModel userModel; IView view; Presenter(IUserModel userModel, IView view) { userModel = userModel; view = view; }
  55. 55. @FMuntenescu interface IView { void setName(String name); }
  56. 56. @FMuntenescu Presenter ModelView 1 … * IView IPresenter
  57. 57. @FMuntenescu ViewModel ModelView 1 … *
  58. 58. @FMuntenescu Model – View – ViewModel
  59. 59. @FMuntenescu ViewModel ModelView 1 … *
  60. 60. @FMuntenescu class User { String firstName; String lastName; Date dateOfBirth; }
  61. 61. @FMuntenescu class User { String firstName; Jane String lastName; Doe Date dateOfBirth; 04.04.1987 }
  62. 62. @FMuntenescu class User { String firstName; Jane String lastName; Doe Date dateOfBirth; 04.04.1987 } Name: Doe, Jane Age: 29
  63. 63. @FMuntenescu class ViewModel { Observable<String> getName() { … } Observable<Integer> getAge() { … } }
  64. 64. @FMuntenescu class ViewModel { Observable<DisplayableUser> getUser() { … } }
  65. 65. @FMuntenescu class DisplayableUser { String mName; int mAge; } class ViewModel { Observable<DisplayableUser> getUser() { … } }
  66. 66. @FMuntenescu @Mock IUserModel userModel; ViewModel viewModel; @Before void setup() { … viewModel = new ViewModel(userModel); }
  67. 67. @FMuntenescu @Mock IUserModel userModel; ViewModel viewModel; @Before public void setup() { … viewModel = new ViewModel(userModel); }
  68. 68. @FMuntenescu @Test public void getUser_emitsCorrectValue() { when(userModel.getUser()) .thenReturn(new User(“Jane”,”Doe”, new Date(4,4,1987)); viewModel.getUser() .subscribe(testSubscriber); testSubscriber.assertValue(expectedUser); }
  69. 69. @FMuntenescu @Test public void getUser_emitsCorrectValue() { when(userModel.getUser()) .thenReturn(new User(“Jane”,”Doe”, new Date(4,4,1987)); viewModel.getUser() .subscribe(testSubscriber); testSubscriber.assertValue(expectedUser); }
  70. 70. @FMuntenescu @Test public void getUser_emitsCorrectValue() { when(userModel.getUser()) .thenReturn(new User(“Jane”,”Doe”, new Date(4,4,1987)); viewModel.getUser() .subscribe(testSubscriber); testSubscriber.assertValue(expectedUser); }
  71. 71. @FMuntenescu @Test public void getUser_emitsCorrectValue() { when(userModel.getUser()) .thenReturn(new User(“Jane”,”Doe”, new Date(4,4,1987)); viewModel.getUser() .subscribe(testSubscriber); testSubscriber.assertValue(expectedUser); }
  72. 72. @FMuntenescu Model – View – Presenter & Model – View – ViewModel
  73. 73. @FMuntenescu class Presenter { void onLoad() { … view.setName(displayName); } } class ViewModel { Observable<String> getName() { … } }
  74. 74. @FMuntenescu Who is the View?
  75. 75. @FMuntenescu ( P | VM )Activity
  76. 76. @FMuntenescu ( P | VM ) Fragment Activity
  77. 77. @FMuntenescu ( P | VM ) Fragment Activity Custom View Custom View
  78. 78. @FMuntenescu class View implements IView { @Inject Presenter presenter; … presenter.onLoad(this);
  79. 79. @FMuntenescu class View { @Inject ViewModel viewModel;
  80. 80. @FMuntenescu Fragment SomeView AnotherView
  81. 81. @FMuntenescu <RelativeLayout> <my.custom.SomeView /> <my.custom.AnotherView /> </RelativeLayout> Fragment SomeView AnotherView
  82. 82. @FMuntenescu <RelativeLayout> <my.custom.SomeView /> <my.custom.AnotherView /> </RelativeLayout> Fragment SomeView AnotherView NewView
  83. 83. @FMuntenescu <RelativeLayout> <my.custom.SomeView /> <my.custom.NewView /> <my.custom.AnotherView /> </RelativeLayout> Fragment AnotherView NewView
  84. 84. @FMuntenescu How to split Views?
  85. 85. @FMuntenescu Complexity Responsibility Reusability
  86. 86. @FMuntenescu What goes where? V ? ( P VM )
  87. 87. @FMuntenescu Does it contain UI logic? View( P | VM ) Yes No
  88. 88. @FMuntenescu ( P | VM ) ModelView
  89. 89. @FMuntenescu ( P | VM ) ModelView
  90. 90. @FMuntenescu How to handle dependencies between Views?
  91. 91. @FMuntenescu Fragment View 1 View 2
  92. 92. @FMuntenescu Fragment View 1 View 2 View 1 View 2
  93. 93. @FMuntenescu JaneFragment View 1 View 2 Doe 4.4.1987 CONTINUE
  94. 94. @FMuntenescu Fragment View 1 View 2 Model
  95. 95. @FMuntenescu Fragment Presenter View 1 Presenter View 2 Presenter
  96. 96. @FMuntenescu Fragment ViewModel View 1 ViewModel View 2 ViewModel
  97. 97. @FMuntenescu How to handle Android lifecycle?
  98. 98. @FMuntenescu onResume / onPause
  99. 99. @FMuntenescu @Override protected void onResume() { … presenter.onLoad(); } @Override protected void onPause() { presenter.onStopLoad(); … }
  100. 100. @FMuntenescu @Override protected void onResume() { … presenter.onLoad(); } @Override protected void onPause() { presenter.onStopLoad(); … }
  101. 101. @FMuntenescu @Override protected void onResume() { … viewModel.getDataStream() .subscribe(…); } @Override protected void onPause() { // unsubscribe … }
  102. 102. @FMuntenescu @Override protected void onResume() { … viewModel.getDataStream() .subscribe(…); } @Override protected void onPause() { // unsubscribe … }
  103. 103. @FMuntenescu onAttachedToWindow / onDetachedFromWindow
  104. 104. @FMuntenescu @Override void onAttachedToWindow() { presenter.onLoad(); … } @Override void onDetachedFromWindow() { … presenter.onStopLoad(); }
  105. 105. @FMuntenescu @Override void onAttachedToWindow() { presenter.onLoad(); … } @Override void onDetachedFromWindow() { … presenter.onStopLoad(); }
  106. 106. @FMuntenescu @Override void onAttachedToWindow() { viewModel.getDataStream() .subscribe(…); … } @Override void onDetachedFromWindow() { … // unsubscribe }
  107. 107. @FMuntenescu @Override void onAttachedToWindow() { viewModel.getDataStream() .subscribe(…); … } @Override void onDetachedFromWindow() { … // unsubscribe }
  108. 108. @FMuntenescu onSaveInstanceState / onRestoreInstanceState
  109. 109. @FMuntenescu @Override void onSaveInstanceState(Bundle state) { state.putAll( presenter/viewModel.getState()); } @Override void onRestoreInstanceState(Bundle state) { presenter/viewModel .restoreState(state); }
  110. 110. @FMuntenescu @Override void onSaveInstanceState(Bundle state) { state.putAll( presenter/viewModel.getState()); } @Override void onRestoreInstanceState(Bundle state) { presenter/viewModel .restoreState(state); }
  111. 111. @FMuntenescu @Override Parcelable onSaveInstanceState() { // save state } @Override void onRestoreInstanceState( Parcelable state) { // restore state }
  112. 112. @FMuntenescu MVC vs MVP vs MVVM
  113. 113. @FMuntenescu Are your Android classes logic free?
  114. 114. @FMuntenescu Can you unit test everything?
  115. 115. @FMuntenescu Do your classes do one thing and one thing only?
  116. 116. @FMuntenescu Robust, stable, testable, modular, easy to extend
  117. 117. @FMuntenescu A Journey Through MV Wonderland jobs@upday.com Google Architecture Blueprints https://github.com/googlesamples/android-architecture MVP vs MVVM example https://github.com/florina-muntenescu/MVPvsMVVM https://upday.github.io/

×