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

A8b79d304b5184e5a5b0a109590f6683?s=128

Danny Preussler

November 11, 2017
Tweet

Transcript

  1. DEVFEST FLORida ViewMODEL IN ACTION the new architecture components @PreusslerBerlin

  2. None
  3. Introducing The architecture components

  4. starring Room LiFe cycle LiveData ViewModel Pagination (new)

  5. ViewModel like in Model-View-ViewModel ?

  6. ViewModel in MVVM world Model ViewModel View View ViewModel Model

  7. in new suggested architecture

  8. in new suggested architecture

  9. Is MVP dead?

  10. 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
  11. 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
  12. 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
  13. Is MVP dead? •Start by putting the ViewModel behind Presenter

  14. In architecture components •A ViewModel provides the data for a

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

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

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

    specific UI •The ViewModel does not know about the View! •Survives configuration change
  18. In architecture components •Remember configuration change can be: •Rotation •Any

    other resize i.e. split screen •Language change
  19. life cycle: rotation onCreate onStart onResume onPause onStop onDestroy onCreate

    onStart onResume ViewModel
  20. life cycle: finish onCreate onStart onResume onPause onStop onDestroy ViewModel

  21. How to use implementation 'android.arch.lifecycle:extensions:1.0.0’ kapt 'android.arch.lifecycle:compiler:1.0.0’

  22. How to use class MyViewModel() : ViewModel() {

  23. How to use class MyViewModel(app: Application) : AndroidViewModel(app) {

  24. How to use class MyViewModel() :ViewModelObservable() { Coming soon Jose

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

    .of(this) .get(MyViewModel::class.java) }
  26. What if… constructor arguments needed?

  27. How to use class MyViewModelFactory :ViewModelProvider.Factory(useCase: MyUseCase) { fun <T:

    ViewModel> create(aClass: Class<T>): T { return MyViewModel(useCase) as T } }
  28. How to use ViewModelProviders .of(this, MyViewModelFactory(usecase)) .get(MyShowsViewModel::class.java)

  29. 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
  30. 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
  31. How to use override fun onStopped() { … } No

    more life cycle forwarding!
  32. What if… I need to clean something when destroyed?

  33. What if… class MyViewModel() : ViewModel() { override fun onCleared()

    { super.onCleared() cleanupSubscriptions() }
  34. How does it survive orientation change?

  35. How does it actually work? class HolderFragment extends Fragment {

    public HolderFragment() { setRetainInstance(true); } …
  36. How does it actually work? String HOLDER_TAG = "android.arch.lifecycle.state.StateProviderH olderFragment";

  37. How does it know the activity is finishing?

  38. How does it actually work? @Override public void onDestroy() {

    super.onDestroy(); mViewModelStore.clear(); }
  39. Can I do it differently? ViewModel is not life cycle

    aware?
  40. It just refuses to die

  41. remember Never hold View or Activity references in the ViewModel!

  42. Tell us more

  43. What if Two Fragments of same Activity ask for same

    ViewModel.class via ViewModelProviders .of(this) .get(MyViewModel::class.java)
  44. Different ViewModels RESULT

  45. What if Two Fragments of same Activity ask for same

    ViewModel.class via ViewModelProviders .of(this) .get(MyViewModel::class.java)
  46. W A I T

  47. result •Fragment and Activity share the same FragmentManager •But implementation

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

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

    ViewModel.class via ViewModelProviders .of(getActivity()) .get(MyViewMode::class).java
  50. result Same ViewModel

  51. Tell us more

  52. Other uses cases communication layer between activities and fragments or

    fragments and fragments
  53. Other uses cases Replace Loaders (plus Room and LiveData/Rx)

  54. Could you Write that?

  55. Could you write that? •What if asked for ViewModel but

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

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

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

    transaction? •You might end up with memory leaks
  59. 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); } } }; …
  60. Does that mean all problems are solved?

  61. 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
  62. but but WHY?

  63. 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?
  64. MeaNS ViewModels gives us rotation But takes away recreation

  65. after The truth •Keep non-UI states in non-UI layer Not

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

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

    in bundle! •Use real caching strategies •Allows updating cache in background
  68. but but EditText might have restored it’s state but the

    ViewModel will not now about it
  69. but but Where to store the UI state?

  70. store the UI state In Bundles!

  71. but but Who owns the UI state?

  72. store the UI state The ViewModel

  73. store the UI state

  74. 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 } ...
  75. lets tweak it override onSaveInstanceState(bundle: Bundle){ super.onSaveInstanceState(bundle); viewModel.writeTo(bundle); }

  76. So what about this LIFE CYCLE THING?

  77. LIFECYCLE is a class that holds the information about the

    lifecycle state of a component
  78. 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
  79. LIFECYCLE OBSERVER class MyListener() : LifecycleObserver { @OnLifecycleEvent(Event.ON_START) fun onStart()

    { … }
  80. LIFECYCLE OBSERVER activity.lifecycle.addObserver(listener)

  81. 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.
  82. AND LIFECYCLE OBSERVER GIVEs US… Process Lifecycle Owner

  83. So SHOULD VIEWMODEL IMPLEMENT LIFE CYCLE OBSERVER?

  84. NOOOOOOOOOOOO

  85. ViewMODEL lives LOngER! Activity Activity ViewModel

  86. IntroduciNG LIVE DATA Activity Activity LiveData LiveData ViewModel

  87. IntroduciNG LIVE DATA •Observable similar to RxJava •Life cycle aware

    •Doesn’t emit when not needed •Memory leaks save
  88. IntroduciNG LIVE DATA class MyViewModel(): ViewModel() { val message =

    MutableLiveData<String>()
  89. IntroduciNG LIVE DATA myModel.message.observe( this, Observer { display(it) })

  90. What if I USE Rx Java?

  91. Rx Java FULL PICTURE Activity ViewModel (un)subscribe

  92. Rx Java FULL PICTURE Activity ViewModel Life cycle aware class

    (un)subscribe (un)subscribe
  93. What if I USE DATA BINDING?

  94. Data binding full picture XML ViewModel bind

  95. 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>
  96. How do I…

  97. .. show a toast class SeriesViewModel : Viewmodel() { …

    @Bindable var error = ObservableField<String>()
  98. .. show a toast viewModel.error.addOnPropertyChangedCallback( object : OnPropertyChangedCallback() { override

    fun onPropertyChanged(…) { showToast(viewModel.error.get() } })
  99. .. show a toast <FrameLayout app:showError="@{viewModel.errorAppeared}"> @BindingAdapter("showError") fun ViewGroup.onErrorAppeared(error: String?){

    errorString?.let { showToast(context, error)) } }
  100. Data binding full picture XML Activity ViewModel (un)bind bind Life

    cycle aware class (un)bind
  101. 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
  102. OR DON’T USE ARCH COMP VIEWMODEL Activity Life cycle ware

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

    •Use the parts you need •Know about life cycle
  104. let`s sum up View Model Its production ready!

  105. 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
  106. Southpark copyright Disclaimer

  107. viacom.tech

  108. View Model IN ACTION @PreusslerBerlin