ViewModelFactory

ViewModelFactory allows us to produce custom ViewModels that allow for the inclusion of arguments in the Constructor (standard ViewModels do not).

To implement a ViewModelFactory, first create a ViewModelFactory class (this example corresponds to the code in the @Entity, @DAO, Build a Database and LiveData posts):

public class AddContactViewModelFactory extends ViewModelProvider.NewInstanceFactory {

    private final AppDatabase mDb;
    private final int mContactId;

    public AddTaskViewModelFactory(AppDatabase mDb, int mContactId) { // Arguments to be passed in
        this.mDb = mDb;
        this.mContactId = mContactId;
    }


    // Note: This can be reused with minor modifications
    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) { // When ViewModelFactory is created it returns a new ViewModel with the arguments fed in
        //noinspection unchecked
        return (T) new AddContactViewModel(mDb, mContactId);
    }
}

Then create the class declared in the ViewModelFactory's create() override:

public class AddContactViewModel extends ViewModel {

    private LiveData<ContactEntry> contactEntry;

    public AddTaskViewModel(AppDatabase database, int contactId) { // Constructor which takes the arguments
        contactEntry = database.contactDao().loadContactById(contactId); // Code which retrieves the LiveData object through the @DAO
    }

    public LiveData<ContactEntry> getContactEntry() { // Method of delivering the data to the Activity
        return contactEntry;
    }
}

In the Activity:

AddContactViewModelFactory addContactViewModelFactory = new AddContactViewModelFactory(mDb, mContactId); // Feed in arguments to the ViewModelFactory
final  AddContactViewModel viewModel = ViewModelProviders.of(this, addContactViewModelFactory).get(AddContactViewModel.class); // Create the View Model, including the ViewModelFactory in the arguments
                viewModel.getContactEntry().observe(this, new Observer<ContactEntry>() { // Observe the LiveData object which is cached in the ViewModel
    @Override
    public void onChanged(@Nullable ContactEntry contactEntry) {
        viewModel.getContactEntry().removeObserver(this); // Not quite sure why we've removed the Observer here
        populateUI(contactEntry); // Apply changes to UI
    }
});