Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MVVM Architecture on Android

petrnohejl
November 24, 2016

MVVM Architecture on Android

Talk about MVVM given at STRV Android Meetup in Nov/2016. I describe my approach using Data Binding Library from Google. Video record: https://www.youtube.com/watch?v=vnBmdKkMLZw. Demo project: https://github.com/petrnohejl/Android-Stocks.

petrnohejl

November 24, 2016
Tweet

More Decks by petrnohejl

Other Decks in Programming

Transcript

  1. WHAT IS MVVM? • Model (data) - View (UI) -

    ViewModel (state & logic) • aka Model - View - Binder Source: https://msdn.microsoft.com/en-us/library/gg405484.aspx
  2. VIEWMODEL • Represents a display logic • Prepares the data

    for presentation • Uses Observer pattern to notify changes
  3. VIEWMODEL • Represents display logic • Prepares the data for

    presentation • Uses Observer pattern to notify changes ViewModel is... • Abstraction of the view exposing public properties and commands • State of the data in the model • Maintains the state of the view • Value converter (raw data to presentation-friendly properties)
  4. MVVM VS. MVP • Binding • One-to-Many relation • Many

    Views can be mapped to one ViewModel • View has a reference to the ViewModel • ViewModel has no information about the View
  5. MOTIVATION • Separation of concerns • Better testability • Follow

    SOLID principles Source: http://tiny-giant-books.com/img/Uncle-Bob-Transparent-Background.png
  6. HOW TO IMPLEMENT LAYERS? • Model (data provider) • View

    (Activity/Fragment/XML) • ViewModel (plain Java or BaseObservable) SOLID
  7. MODEL RESPONSIBILITIES (DATA) • Retrofit • SQLite db • Realm

    db • Firebase • SharedPreferences • Geolocation • Broadcasts
  8. VIEW RESPONSIBILITIES (UI) • Working with android.view, android.widget, etc. •

    Showing Dialogs, Toasts, Snackbars • Event listeners • Starting Activities • Handling Menu • Handling permissions • Other Android specific stuff & methods which require reference to the Activity Context
  9. VIEWMODEL RESPONSIBILITIES (STATE & LOGIC) • Exposing state (progress, offline,

    empty, error, etc.) • Exposing data • Handling visibility • Handling Extras & Arguments (Bundle) • Input validation • Executing data calls in the Model • Executing UI commands in the View
  10. WHAT ABOUT ANDROID API? • ViewModel layer should be separated

    from Android specific classes • Permissions, Intents, Menu etc. in Activity/Fragment
  11. WHAT ABOUT ANDROID API? • Separate UI stuff from Android

    stuff in the View or not? Activity implements View onCreate() onCreateOptionsMenu() onRequestPermissionsResult() showDialog() onItemClick()
  12. WHAT ABOUT CONTEXT? • ViewModel should use only the Application

    Context Source: https://possiblemobile.com/2013/06/context/
  13. EVENT LISTENERS • Defined in the View • Decoupled -

    separate business logic from UI • Example - 3 screens, loading data on different actions ViewModel loadUsers() onRefreshButtonClick() onDialogPositiveClick() Activity #1 onRefreshButtonClick() Activity #3 viewModel.onGeolocationRespond() Activity #2 onDialogPositiveClick() SOLID
  14. @{ EXPRESSIONS } <View android:visibility="@{age < 18 ? View.GONE :

    View.VISIBLE}" ... /> What’s wrong about this?
  15. @{ EXPRESSIONS } android:visibility="@{age < 18 ? View.GONE : View.VISIBLE}"

    What is wrong: ❌ Mixing display logic with UI ❌ Breaking single responsibility (to show data) ❌ Impossible to unit test and hard to debug Better way: • Views should be as dumb as possible • Primitive expressions are probably OK
  16. TESTING Model and ViewModel • JUnit & Mockito (unit tests)

    • Pure Java without Android API View • Espresso (UI tests) • No logic
  17. PROS & CONS ✅ Readable code ✅ Maintainable code ✅

    Testable code ✅ SOLID code ✅ No god classes ❌ View = Java + XML ❌ Mixed Android API + View
  18. VIEW public interface StockDetailView { void onButtonClick(View view); } public

    class StockDetailFragment extends BaseFragment<StockDetailView, StockDetailViewModel> implements StockDetailView { private FragmentStockDetailBinding mBinding; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mBinding = FragmentStockDetailBinding. inflate(inflater); mBinding.setView( this); mBinding.setViewModel(getViewModel()); return mBinding.getRoot(); } @Override public void onButtonClick(View view) { getViewModel().loadStock(); } ... }
  19. XML LAYOUT <variable name="view" type="com.example.ui.StockDetailView" /> <variable name="viewModel" type="com.example.viewmodel.StockDetailViewModel" />

    <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{view.onButtonClick}" ... /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewModel.stock.name}" ... />
  20. VIEWMODEL public class StockDetailViewModel extends BaseViewModel<StockDetailView> { public final ObservableField<StatefulLayout.State>

    state = new ObservableField<>(); public final ObservableField<StockEntity> stock = new ObservableField<>(); private DataProvider mDataProvider; // represents model @Override public void onStart() { super.onStart(); if(stock.get() == null) loadStock(); } public void loadStock() { if(NetworkUtility. isOnline(StocksApplication. getContext())) { state.set(StatefulLayout.State. PROGRESS); mDataProvider.loadStock(...); // retrieves data from model and updates stock and state fields } else { state.set(StatefulLayout.State. OFFLINE); } } ... }
  21. DEMO PROJECT • https://github.com/petrnohejl/Android-Stocks ◦ MVVM architecture ◦ Data binding

    ◦ RecyclerView ◦ RxJava ◦ Retrolambda ◦ OkHttp ◦ Retrofit ◦ GSON ◦ Glide ◦ LeakCanary
  22. LIBRARIES & EXAMPLES • https://github.com/inloop/AndroidViewModel • https://github.com/jakubkinst/Android-ViewModelBinding/ • https://github.com/fabioCollini/mv2m •

    https://github.com/hitherejoe/MVVM_Hacker_News • https://github.com/ivacf/archi • https://github.com/erikcaffrey/People-MVVM • https://github.com/radzio/android-data-binding-recyclerview • https://github.com/radzio/android-data-binding-command • https://github.com/Nilzor/mvp-to-mvvm-transition • https://github.com/googlesamples/android-architecture
  23. ARTICLES • https://medium.com/@artem_zin/m-model-from-mvc-mvp-in-android-flow-and-mortar-bd1e50c45395#.dp51cjddi • https://medium.com/android-news/android-architecture-2f12e1c7d4db#.eq9u6h3zl • https://medium.com/ribot-labs/approaching-android-with-mvvm-8ceec02d5442 • https://medium.com/ribot-labs/android-application-architecture-8b6e34acda65#.okk4mtrc5 •

    https://medium.com/mobiwise-blog/android-basic-project-architecture-for-mvp-72f4b33252d0#.ncwed522y • http://cases.azoft.com/mvvm-android-data-binding/ • http://blog.stablekernel.com/mvvm-on-android-using-the-data-binding-library/ • http://tech.vg.no/2015/07/17/android-databinding-goodbye-presenter-hello-viewmodel/ • http://blog.grio.com/2016/03/building-android-apps-with-mvvm-and-data-binding.html • https://medium.com/cobe-mobile/architecting-android-with-data-binding-and-mvvm-in-mind-8874bbec0b0d • http://www.codeprogression.com/2015/10/30/android-presentation-model/ • https://catinean.com/2015/05/31/how-you-can-go-wrong-with-the-new-data-binding-api/ • https://corner.squareup.com/2014/10/advocating-against-android-fragments.html • https://www.bignerdranch.com/blog/shades-of-mvvm/ • https://medium.com/upday-devs/android-architecture-patterns-part-3-model-view-viewmodel-e7eeee76b73b • https://medium.com/upday-devs/mvvm-rxjava-learnings-1819423f9592 • https://medium.com/@Miqubel/refactoring-to-mvvm-40ebafff43de#.yhj3vy8pp • https://medium.com/@manuelvicnt/rxjava2-android-mvvm-lifecycle-app-structure-with-retrofit-2-cf903849f49e • https://medium.com/@hiBrianLee/writing-testable-android-mvvm-app-prelude-e49f7e6223