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

Viewmodel in action: DevFest Florida 2018

Viewmodel in action: DevFest Florida 2018

At Google I/O we got the Android architecture components. One of its most interesting concepts is the new ViewModel. How does it work? How do I plug it into my app? Can I use it without any of the other components? Can I plug it into an existing MVVM or how would I build MVVM with Google's ViewModel? Let's do a deep dive into the topic

Danny Preussler

November 11, 2017
Tweet

More Decks by Danny Preussler

Other Decks in Technology

Transcript

  1. Is MVP dead? It’s like Java and Kotlin: •MVP will

    stay for quite some time •There is a new cooler kid in town that won’t leave
  2. Is MVP dead? It’s like Java and Kotlin: •MVP will

    stay for quite some time •There is a new cooler kid in town that won’t leave
  3. Is MVP dead? It’s like Java and Kotlin: •MVP will

    stay for quite some time •There is a new cooler kid in town that won’t leave
  4. In architecture components •A ViewModel provides the data for a

    specific UI •The ViewModel does not know about the View! •Survives configuration change
  5. In architecture components •A ViewModel provides the data for a

    specific UI •The ViewModel does not know about the View! •Survives configuration change
  6. In architecture components •A ViewModel provides the data for a

    specific UI •The ViewModel does not know about the View! •Survives configuration change
  7. In architecture components •A ViewModel provides the data for a

    specific UI •The ViewModel does not know about the View! •Survives configuration change
  8. How to use class MyViewModel() :ViewModelObservable() { Coming soon Jose

    Alcérreca, Google https://medium.com/@dpreussler/add-the-new-viewmodel-to-your-mvvm-36bfea86b159
  9. How to use override fun onCreate(...) { model = ViewModelProviders

    .of(this) .get(MyViewModel::class.java) }
  10. How to use class MyViewModelFactory :ViewModelProvider.Factory(useCase: MyUseCase) { fun <T:

    ViewModel> create(aClass: Class<T>): T { return MyViewModel(useCase) as T } }
  11. How to use •Always try to build your own Factory

    •Default factory uses newInstance() which is some hundred times slower than new calls (reflection) https://speakerdeck.com/dpreussler/comparing-dependency-injection- frameworks-and-internals-for-android
  12. How to use •Always try to build your own Factory

    •Default factory uses newInstance() which is some hundred times slower than new calls (reflection) https://speakerdeck.com/dpreussler/comparing-dependency-injection- frameworks-and-internals-for-android
  13. How does it actually work? class HolderFragment extends Fragment {

    public HolderFragment() { setRetainInstance(true); } …
  14. How does it actually work? @Override public void onDestroy() {

    super.onDestroy(); mViewModelStore.clear(); }
  15. What if Two Fragments of same Activity ask for same

    ViewModel.class via ViewModelProviders .of(this) .get(MyViewModel::class.java)
  16. What if Two Fragments of same Activity ask for same

    ViewModel.class via ViewModelProviders .of(this) .get(MyViewModel::class.java)
  17. result •Fragment and Activity share the same FragmentManager •But implementation

    uses Activity’s FragmentManager but ChildFragmentManager for Fragments
  18. result •Fragment and Activity share the same FragmentManager •But implementation

    uses Activity’s FragmentManager but ChildFragmentManager for Fragments
  19. What if Two Fragments of same Activity ask for same

    ViewModel.class via ViewModelProviders .of(getActivity()) .get(MyViewMode::class).java
  20. Could you write that? •What if asked for ViewModel but

    fragment transaction not done yet? •You might end up with duplicates
  21. Could you write that? •What if asked for ViewModel but

    fragment transaction not done yet? •You might end up with duplicates
  22. Could you write that? static class HolderFragmentManager { private Map<Activity,

    HolderFragment> mNotCommittedActivityHolders = new HashMap<>(); private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>(); …
  23. Could you write that? •What if activity dies before fragment

    transaction? •You might end up with memory leaks
  24. Could you write that? private ActivityLifecycleCallbacks mActivityCallbacks = new EmptyActivityLifecycleCallbacks()

    { @Override public void onActivityDestroyed(Activity activity) { HolderFragment fragment = mNotCommittedActivityHolders.remove(activity); if (fragment != null) { Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity); } } }; …
  25. all problems solved? ViewModels provide a convenient way to retain

    data across configuration changes but they are not persisted if the application is killed by the operating system https://developer.android.com/topic/libraries/architecture/viewmodel.html#viewm odel_vs_savedinstancestate
  26. Why? The data saved via onSaveInstanceState is kept in the

    system process memory and the Android OS allows you to keep only a very small amount of data so it is not a good place to keep actual data for your app. TransactionTooLargeException anyone?
  27. after The truth •Keep non-UI states in non-UI layer Not

    in bundle! •Use real caching strategies •Allows updating cache in background
  28. after The truth •Keep non-UI states in non-UI layer Not

    in bundle! •Use real caching strategies •Allows updating cache in background
  29. after The truth •Keep non-UI states in non-UI layer Not

    in bundle! •Use real caching strategies •Allows updating cache in background
  30. lets tweak it class MyModelFactory(val bundle: Bundle?) :ViewModelProvider.Factory() { …

    fun <T: ViewModel> create(aClass: Class<T>): T { return MyViewModel().apply { readFrom(bundle) } as T } ...
  31. LIFECYCLE OWNER is a single method interface that denotes that

    the class has a Lifecycle. Fragments and Activities in Support Library 26.1.0+ already implement
  32. LIFECYCLE OBSERVER activity.lifecycle.addObserver(listener) An observer added with a Lifecycle will

    be automatically removed if the corresponding Lifecycle moves to Lifecycle.State#DESTROYED state.
  33. IntroduciNG LIVE DATA •Observable similar to RxJava •Life cycle aware

    •Doesn’t emit when not needed •Memory leaks save
  34. ViewModel in data binding <TextView … android:id="@+id/all_shows_item_title" android:text="@{viewModel.title}" /> <android.support.v7.widget.CardView

    … android:onClick="@{() -> viewModel.onClicked()}"> <data> <variable name="viewModel" type="com.vmn.playplex.main.allshows.SeriesViewModel"/> </data>
  35. .. show a toast class SeriesViewModel : Viewmodel() { …

    @Bindable var error = ObservableField<String>()
  36. WAYS TO OBSERVE DATA from VM? •Data binding Observable from

    xml or code, might need unregister •RxJava Observable from code, needs unregister •LiveData Observable, from code, no unregister, life cycle aware
  37. OR DON’T USE ARCH COMP VIEWMODEL Activity Life cycle ware

    ViewModel Repository Activity Life cycle ware ViewModel
  38. let`s sum up •Well designed API •Goal: common architecture language

    •Use the parts you need •Know about life cycle
  39. Want to know more • https://medium.com/@dpreussler/add-the-new- viewmodel-to-your-mvvm-36bfea86b159 • https://proandroiddev.com/customizing-the-new- viewmodel-cf28b8a7c5fc

    • http://hannesdorfmann.com/android/arch-components- purist • https://blog.stylingandroid.com/architecture-components- viewmodel/ • https://www.youtube.com/watch?v=QrbhPcbZv0I • https://www.youtube.com/watch?v=c9-057jC1ZA