MVVM, Viewmodel and architecture components

MVVM, Viewmodel and architecture components

UAmobile, Kiev

A8b79d304b5184e5a5b0a109590f6683?s=128

Danny Preussler

November 25, 2017
Tweet

Transcript

  1. #UAMOBILE ViewMODEL & MVVM & databinding architecture components in ACTION

    @PreusslerBerlin
  2. None
  3. Introducing The architecture components

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

  5. in new suggested architecture

  6. in new suggested architecture

  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. In architecture components •A ViewModel provides the data for a

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

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

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

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

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

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

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

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

  17. How to use override fun onCreate(...) { model = ViewModelProviders

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

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

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

  21. 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
  22. 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
  23. How to use override fun onStopped() { … } No

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

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

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

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

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

  29. How does it know the activity is finishing?

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

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

    aware?
  32. It just refuses to die

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

  34. Tell us more

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

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

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

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

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

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

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

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

  43. Tell us more

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

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

  46. Tell us more

  47. ViewModel like in Model-View-ViewModel ?

  48. Model-View-ViewModel

  49. ViewModel in MVVM world Model ViewModel View View Presenter Model

  50. ViewModel in MVVM world Model ViewModel View View ViewModel Model

  51. Is MVP dead?

  52. 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
  53. 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
  54. 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
  55. Is MVP dead? •Start by putting the ViewModel behind Presenter

  56. Binding to ViewMODELS Activity Activity ViewModel (un)bind (un)bind

  57. IntroduciNG LIVE DATA Activity Activity LiveData LiveData ViewModel

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

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

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

  61. Is there something better?

  62. Databinding!

  63. Data binding full picture XML ViewModel bind

  64. Solves the one big android question once and forever who

    is the view?
  65. ViewModel in data binding <TextView … android:id="@+id/all_shows_item_title" android:text="@{viewModel.title}" /> <data>

    <variable name="viewModel" type="com.vmn.playplex.main.allshows.AllShowsViewModel"/> </data>
  66. ViewModel in data binding <android.support.v7.widget.CardView … android:onClick="@{() -> viewModel.onClicked()}"> <data>

    <variable name="viewModel" type="com.vmn.playplex.main.allshows.AllShowsViewModel"/> </data>
  67. How to use class AllShowsViewModel: ViewModelObservable() { var title :

    CharSequence = ""
  68. How to use class AllShowsViewModel: ViewModelObservable() { @Bindable var title

    : CharSequence = "" private set(value) { if (field != value) { field = value notifyPropertyChanged(BR.title) } }
  69. How to use class AllShowsViewModel: ViewModelObservable() { @Bindable var title

    by bindable<CharSequence>("") private set Custom property delegate
  70. How to use class AllShowsFragment : Fragment () { @Inject

    lateinit var showsViewModel: AllShowsViewModel
  71. How to use class AllShowsFragment : Fragment () { @Inject

    lateinit var showsViewModel: AllShowsViewModel override fun onCreateView(…):View? =
  72. How to use class AllShowsFragment : Fragment () { @Inject

    lateinit var showsViewModel: AllShowsViewModel override fun onCreateView(…):View? = FragmentShowsBinding.inflate( inflater, container, false).apply { viewModel = showsViewModel }).root
  73. How to use class AllShowsFragment : Fragment () { @Inject

    lateinit var showsViewModel: AllShowsViewModel override fun onCreateView(…):View? = FragmentShowsBinding.inflate( inflater, container, false).apply { viewModel = showsViewModel }).root fragment_shows.xml
  74. How to use class MyViewModel() :ViewModelObservable() { Coming soon Jose

    Alcérreca, Google https://medium.com/@dpreussler/add-the-new-viewmodel-to-your-mvvm-36bfea86b159
  75. How do I…

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

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

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

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

    cycle aware class (un)bind
  80. 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
  81. let`s sum up •Architecture components are here •Use the parts

    you need •Goal: common architecture language •Databinding rocks •Know about life cycle
  82. 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
  83. Southpark copyright Disclaimer

  84. viacom.tech

  85. View Model IN ACTION @PreusslerBerlin

  86. Does that mean all problems are solved?

  87. 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
  88. but but WHY?

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

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

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

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

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

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

  96. store the UI state In Bundles!

  97. but but Who owns the UI state?

  98. store the UI state The ViewModel

  99. store the UI state

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