How to use ViewModel and ViewModelsProviders in Android

Issue #363

ViewModels a simple example

https://medium.com/androiddevelopers/viewmodels-a-simple-example-ed5ac416317e

Rotating a device is one of a few configuration changes that an app can go through during its lifetime, including keyboard availability and changing the device’s language. All of these configuration changes cause the Activity to be torn down and recreated

The ViewModel class is designed to hold and manage UI-related data in a life-cycle conscious way. This allows data to survive configuration changes such as screen rotations.

The ViewModel exists from when the you first request a ViewModel (usually in the onCreate the Activity) until the Activity is finished and destroyed. onCreate may be called several times during the life of an Activity, such as when the app is rotated, but the ViewModel survives throughout.

Storing an Application context in a ViewModel is okay because an Application context is tied to the Application lifecycle. This is different from an Activity context, which is tied to the Activity lifecycle. In fact, if you need an Application context, you should extend AndroidViewModel which is simply a ViewModel that includes an Application reference.

The first time the ViewModelProviders.of method is called by MainActivity, it creates a new ViewModel instance. When this method is called again, which happens whenever onCreate is called, it will return the pre-existing ViewModel associated with the specific Court-Counter MainActivity

1
ViewModelProviders.of(<THIS ARGUMENT>).get(ScoreViewModel.class);

This allows you to have an app that opens a lot of different instances of the same Activity or Fragment, but with different ViewModel information

Dive deep into Android’s ViewModel — Android Architecture Components

https://android.jlelse.eu/dive-deep-into-androids-viewmodel-android-architecture-components-e0a7ded26f70

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Utilities methods for {@link ViewModelStore} class.
*/
public class ViewModelProviders {
/**
* Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given Activity
* is alive. More detailed explanation is in {@link ViewModel}.
* <p>
* It uses {@link ViewModelProvider.AndroidViewModelFactory} to instantiate new ViewModels.
*
* @param activity an activity, in whose scope ViewModels should be retained
* @return a ViewModelProvider instance
*/
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
ViewModelProvider.AndroidViewModelFactory factory =
ViewModelProvider.AndroidViewModelFactory.getInstance(
checkApplication(activity));
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}

}

It seems like ViewModelProviders.of is just a factory of ViewModelProvider, which depends upon ViewModelFactory and a ViewModelStore.

1
2
MyViewModelFactory factory = new MyViewModelFactory(data1, data2);
ViewModelProviders.of(this, factory).get(MyViewModel.class);
1
2
3
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
}

HolderFragment

HolderFragment is a regular Android Headless Fragment. It is the scope where all ViewModels inside the ViewModelStore will live.

1
2
3
4
5

public class HolderFragment extends Fragment implements ViewModelStoreOwner {
private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();
private ViewModelStore mViewModelStore = new ViewModelStore();
}
1
2
3
4
static class HolderFragmentManager {
private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>();
}

Who owns the HolderFragment?

The HolderFragment has an inner static class named HolderFragmentManager. The HolderFragmentManager creates and manages HolderFragment instances.
After creating the instances it associates them with an Activity or Fragment.

The whole process is done using the methods holderFragmentFor(Activity) and holderFragmentFor(Fragment).

How does HolderFragment retains the state ?

By setting retain instance to true and not providing a view, the HolderFragment becomes essentially a headless Fragment that is retained for as long as the Activity is not destroyed.

1
2
3
public HolderFragment() {
setRetainInstance(true);
}

void setRetainInstance (boolean retain)

Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. If set, the fragment lifecycle will be slightly different when an activity is recreated:

Retrieving ViewModel instance

1
get(MyViewModel.class)

It tries to retrieve a MyViewModel instance from the store. If none is there, it uses the factory to create it and then stores it into HashMap<String, ViewModel>. In order to retrieve the already created ViewModel, it generates a key from the class qualified name.

Comments