DEVFEST FLORida
ViewMODEL IN ACTION
the new architecture components
@PreusslerBerlin
Slide 2
Slide 2 text
No content
Slide 3
Slide 3 text
Introducing
The
architecture
components
Slide 4
Slide 4 text
starring
Room
LiFe cycle
LiveData
ViewModel
Pagination (new)
Slide 5
Slide 5 text
ViewModel
like in
Model-View-ViewModel
?
Slide 6
Slide 6 text
ViewModel in MVVM world
Model
ViewModel
View
View ViewModel Model
Slide 7
Slide 7 text
in new suggested architecture
Slide 8
Slide 8 text
in new suggested architecture
Slide 9
Slide 9 text
Is MVP
dead?
Slide 10
Slide 10 text
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
Slide 11
Slide 11 text
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
Slide 12
Slide 12 text
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
Slide 13
Slide 13 text
Is MVP dead?
•Start by putting the ViewModel behind
Presenter
Slide 14
Slide 14 text
In architecture components
•A ViewModel provides the data for a specific UI
•The ViewModel does not know about the View!
•Survives configuration change
Slide 15
Slide 15 text
In architecture components
•A ViewModel provides the data for a specific UI
•The ViewModel does not know about the View!
•Survives configuration change
Slide 16
Slide 16 text
In architecture components
•A ViewModel provides the data for a specific UI
•The ViewModel does not know about the View!
•Survives configuration change
Slide 17
Slide 17 text
In architecture components
•A ViewModel provides the data for a specific UI
•The ViewModel does not know about the View!
•Survives configuration change
Slide 18
Slide 18 text
In architecture components
•Remember configuration change can be:
•Rotation
•Any other resize i.e. split screen
•Language change
life cycle: finish
onCreate
onStart
onResume
onPause
onStop
onDestroy
ViewModel
Slide 21
Slide 21 text
How to use
implementation
'android.arch.lifecycle:extensions:1.0.0’
kapt 'android.arch.lifecycle:compiler:1.0.0’
Slide 22
Slide 22 text
How to use
class MyViewModel()
: ViewModel() {
Slide 23
Slide 23 text
How to use
class MyViewModel(app: Application)
: AndroidViewModel(app) {
Slide 24
Slide 24 text
How to use
class MyViewModel()
:ViewModelObservable() {
Coming soon
Jose Alcérreca, Google
https://medium.com/@dpreussler/add-the-new-viewmodel-to-your-mvvm-36bfea86b159
Slide 25
Slide 25 text
How to use
override fun onCreate(...) {
model = ViewModelProviders
.of(this)
.get(MyViewModel::class.java)
}
Slide 26
Slide 26 text
What if…
constructor arguments needed?
Slide 27
Slide 27 text
How to use
class MyViewModelFactory
:ViewModelProvider.Factory(useCase: MyUseCase) {
fun create(aClass: Class): T {
return MyViewModel(useCase) as T
}
}
Slide 28
Slide 28 text
How to use
ViewModelProviders
.of(this, MyViewModelFactory(usecase))
.get(MyShowsViewModel::class.java)
Slide 29
Slide 29 text
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
Slide 30
Slide 30 text
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
Slide 31
Slide 31 text
How to use
override fun onStopped() {
…
}
No more life cycle forwarding!
Slide 32
Slide 32 text
What if…
I need to clean something when destroyed?
Slide 33
Slide 33 text
What if…
class MyViewModel() : ViewModel() {
override fun onCleared() {
super.onCleared()
cleanupSubscriptions()
}
Slide 34
Slide 34 text
How does
it survive
orientation change?
Slide 35
Slide 35 text
How does it actually work?
class HolderFragment extends Fragment {
public HolderFragment() {
setRetainInstance(true);
}
…
Slide 36
Slide 36 text
How does it actually work?
String HOLDER_TAG =
"android.arch.lifecycle.state.StateProviderH
olderFragment";
Slide 37
Slide 37 text
How does
it know
the activity
is finishing?
Slide 38
Slide 38 text
How does it actually work?
@Override
public void onDestroy() {
super.onDestroy();
mViewModelStore.clear();
}
Slide 39
Slide 39 text
Can I do it differently?
ViewModel is not life cycle aware?
Slide 40
Slide 40 text
It just
refuses to
die
Slide 41
Slide 41 text
remember
Never hold View or Activity references
in the ViewModel!
Slide 42
Slide 42 text
Tell us more
Slide 43
Slide 43 text
What if
Two Fragments
of same Activity
ask for same ViewModel.class via
ViewModelProviders
.of(this)
.get(MyViewModel::class.java)
Slide 44
Slide 44 text
Different ViewModels
RESULT
Slide 45
Slide 45 text
What if
Two Fragments
of same Activity
ask for same ViewModel.class via
ViewModelProviders
.of(this)
.get(MyViewModel::class.java)
Slide 46
Slide 46 text
W
A
I
T
Slide 47
Slide 47 text
result
•Fragment and Activity share the same
FragmentManager
•But implementation uses
Activity’s FragmentManager but
ChildFragmentManager for Fragments
Slide 48
Slide 48 text
result
•Fragment and Activity share the same
FragmentManager
•But implementation uses
Activity’s FragmentManager but
ChildFragmentManager for Fragments
Slide 49
Slide 49 text
What if
Two Fragments
of same Activity
ask for same ViewModel.class via
ViewModelProviders
.of(getActivity())
.get(MyViewMode::class).java
Slide 50
Slide 50 text
result
Same ViewModel
Slide 51
Slide 51 text
Tell us more
Slide 52
Slide 52 text
Other uses cases
communication layer between
activities and fragments
or
fragments and fragments
Slide 53
Slide 53 text
Other uses cases
Replace Loaders
(plus Room and LiveData/Rx)
Slide 54
Slide 54 text
Could you
Write that?
Slide 55
Slide 55 text
Could you write that?
•What if asked for ViewModel
but fragment transaction not done yet?
•You might end up with duplicates
Slide 56
Slide 56 text
Could you write that?
•What if asked for ViewModel
but fragment transaction not done yet?
•You might end up with duplicates
Slide 57
Slide 57 text
Could you write that?
static class HolderFragmentManager {
private Map
mNotCommittedActivityHolders = new HashMap<>();
private Map
mNotCommittedFragmentHolders = new HashMap<>();
…
Slide 58
Slide 58 text
Could you write that?
•What if activity dies before fragment
transaction?
•You might end up with memory leaks
Slide 59
Slide 59 text
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);
}
}
};
…
Slide 60
Slide 60 text
Does that mean
all problems are solved?
Slide 61
Slide 61 text
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
Slide 62
Slide 62 text
but but
WHY?
Slide 63
Slide 63 text
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?
Slide 64
Slide 64 text
MeaNS
ViewModels gives us rotation
But takes away recreation
Slide 65
Slide 65 text
after The truth
•Keep non-UI states in non-UI layer
Not in bundle!
•Use real caching strategies
•Allows updating cache in background
Slide 66
Slide 66 text
after The truth
•Keep non-UI states in non-UI layer
Not in bundle!
•Use real caching strategies
•Allows updating cache in background
Slide 67
Slide 67 text
after The truth
•Keep non-UI states in non-UI layer
Not in bundle!
•Use real caching strategies
•Allows updating cache in background
Slide 68
Slide 68 text
but but
EditText might have restored it’s state
but the ViewModel will not now about it
Slide 69
Slide 69 text
but but
Where to store the UI state?
Slide 70
Slide 70 text
store the UI state
In Bundles!
Slide 71
Slide 71 text
but but
Who owns the UI state?
Slide 72
Slide 72 text
store the UI state
The ViewModel
Slide 73
Slide 73 text
store the UI state
Slide 74
Slide 74 text
lets tweak it
class MyModelFactory(val bundle: Bundle?)
:ViewModelProvider.Factory() {
…
fun create(aClass: Class): T {
return MyViewModel().apply {
readFrom(bundle)
} as T
}
...
Slide 75
Slide 75 text
lets tweak it
override onSaveInstanceState(bundle: Bundle){
super.onSaveInstanceState(bundle);
viewModel.writeTo(bundle);
}
Slide 76
Slide 76 text
So what
about this
LIFE CYCLE
THING?
Slide 77
Slide 77 text
LIFECYCLE
is a class that holds the information
about the lifecycle state of a component
Slide 78
Slide 78 text
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
Slide 79
Slide 79 text
LIFECYCLE OBSERVER
class MyListener() : LifecycleObserver {
@OnLifecycleEvent(Event.ON_START)
fun onStart() {
…
}
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.
Slide 82
Slide 82 text
AND LIFECYCLE OBSERVER GIVEs US…
Process
Lifecycle
Owner
Slide 83
Slide 83 text
So SHOULD
VIEWMODEL
IMPLEMENT LIFE
CYCLE OBSERVER?
IntroduciNG LIVE DATA
Activity
Activity
LiveData
LiveData
ViewModel
Slide 87
Slide 87 text
IntroduciNG LIVE DATA
•Observable similar to RxJava
•Life cycle aware
•Doesn’t emit when not needed
•Memory leaks save
Slide 88
Slide 88 text
IntroduciNG LIVE DATA
class MyViewModel(): ViewModel() {
val message =
MutableLiveData()
Slide 89
Slide 89 text
IntroduciNG LIVE DATA
myModel.message.observe(
this,
Observer { display(it) })
Slide 90
Slide 90 text
What if I USE
Rx Java?
Slide 91
Slide 91 text
Rx Java FULL PICTURE
Activity
ViewModel
(un)subscribe
Slide 92
Slide 92 text
Rx Java FULL PICTURE
Activity
ViewModel
Life cycle
aware class (un)subscribe
(un)subscribe
Slide 93
Slide 93 text
What if I USE
DATA BINDING?
Slide 94
Slide 94 text
Data binding full picture
XML
ViewModel
bind
Slide 95
Slide 95 text
ViewModel in data binding
Slide 96
Slide 96 text
How do I…
Slide 97
Slide 97 text
.. show a toast
class SeriesViewModel : Viewmodel() {
…
@Bindable
var error = ObservableField()
Slide 98
Slide 98 text
.. show a toast
viewModel.error.addOnPropertyChangedCallback(
object : OnPropertyChangedCallback() {
override fun onPropertyChanged(…) {
showToast(viewModel.error.get()
}
})
Slide 99
Slide 99 text
.. show a toast
@BindingAdapter("showError")
fun ViewGroup.onErrorAppeared(error: String?){
errorString?.let {
showToast(context, error))
}
}
Slide 100
Slide 100 text
Data binding full picture
XML
Activity ViewModel
(un)bind
bind
Life cycle
aware class (un)bind
Slide 101
Slide 101 text
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
Slide 102
Slide 102 text
OR DON’T USE ARCH COMP VIEWMODEL
Activity
Life cycle
ware
ViewModel
Repository
Activity
Life cycle
ware
ViewModel
Slide 103
Slide 103 text
let`s sum up
•Well designed API
•Goal: common architecture
language
•Use the parts you need
•Know about life cycle
Slide 104
Slide 104 text
let`s sum up
View
Model
Its production ready!
Slide 105
Slide 105 text
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