ViewModel

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

To get an instance of ViewModel, you can just use ViewModelProviders class.

YourViewModel model = ViewModelProviders.of(<Your UI controller>).get(<Your ViewModel>.class)

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

ViewModels only survive configuration change-related destruction; they do not survive the process being stopped. This makes ViewModels a replacement for using a fragment with setRetainInstance(true) (in fact ViewModels use a fragment with setRetainInstance set to true behind the scenes).

ViewModels are not a replacement for persistence — persist your data like normal when it’s changed. A combination of ViewModels, onSaveInstanceState() and local persistence can save and restore UI state efficiently.

Implement a ViewModel

ViewModel objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance. When the owner activity is finished, the framework calls the ViewModel objects's onCleared() method so that it can clean up resources.

Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.

 public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<Users>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asyncronous operation to fetch users.
    }
}
public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

Note: ViewModels should not store objects with Contexts, such as activities, fragments or even Views. This is because these objects are meant to have shorter lifespans than the view model. Storing a reference to these objects will keep them from getting garbage collected, which causes a memory leak.

Sometimes you might need an Application context (as opposed to an Activity context) for use with things like system services. 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 lifecycle of a ViewModel

Lifecycle

As a reminder, when an app processes is stopped due to resource constraints, it’s stopped without ceremony and no additional lifecycle callbacks are called. This means that you can’t rely on onDestroy being called. You do not have a chance to persist data at the time of process shutdown. Therefore, if you want to be the most sure that you won’t lose data, persist it as soon as the user enters it. This means that even if your app process is shut down due to resource constraints or if the device runs out of battery, the data will be saved. If you’re willing to concede losing data in instances of sudden device shutdown, you can save the data in the onStop() callback, which happens right as the activity is going into the background.

ViewModels are not a replacement for onSaveInstanceState() because they only survive configuration change related destruction; they do not survive the OS stopping the app’s process.

Share data between fragments

Fragments can share data with a ViewModel.

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}

public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends Fragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // Update the UI.
        });
    }
}

Notice that both fragments use getActivity() when getting the ViewModelProvider. As a result, both fragments receive the same SharedViewModel instance, which is scoped to the activity.

This approach offers the following benefits:

  • The activity does not need to do anything, or know anything about this communication.
  • Fragments don't need to know about each other besides the SharedViewModel contract. If one of the fragments disappears, the other one keeps working as usual.
  • Each fragment has its own lifecycle, and is not affected by the lifecycle of the other one. If one fragment replaces the other one, the UI continues to work without any problems

Keeping in sync with the Database

The ViewModel ensures that the data survives a device configuration change. Room informs your LiveData when the database changes, and the LiveData, in turn, updates your UI with the revised data.

Room with a ViewModel

Use a repository to handle this.

Lifecycle Aware Data Loading with Architecture Components

results matching ""

    No results matching ""