Robert J. Clegg
Robert J. Clegg

Reputation: 7360

Making changes to LiveData to "redo" work in ViewModel

So, I have just started experimenting with LiveData - I am busy with a new project, where I am using ViewModel as well as LiveData - with some of the RESTFul services I use to fetch data, they take no parameters and return some data.

A typical setup of the MVVM paradigm with LiveData looks much like this:

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

Now when we leave this activity, and go to a new activity, by using an Intent or some other means, and not pressing the back button (So, finalize is not called) - and then come back to MyActivity - we of course don't fetch the users again, as we should still have that data.

However, what if we did want to fetch them again?

The only way to do this properly, from what I have looked at, seems to call "setValue" on the getUsers() LiveData object

Something like this:

public class MyActivity extends AppCompatActivity {
    public void onResume() {
     viewModel.setActive(true); 
    }
}

And the ViewModel would look like this:

  private final MutableLiveData<Boolean> activeLiveData = new MutableLiveData<>();

 ViewModel(ViewModelRepo repo){
      this.repo = repo;

      results = Transformations.switchMap(activeLiveData, active ->{
        if(active){
          return repo.getUsers();
        }else {
          return AbsentLiveData.create(); //"Null live data"
        }
      });
  }

   LiveData<Users>> getUsers() {
    return results;
  }

 //This could be called "update" with no params 
  void setActive(boolean active) {
    activeLiveData.setValue(active);
  }

The one reason I have decided to do it like this is because Google does not want us doing this:

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    public MyViewModel(PostalCodeRepository repository) {
       this.repository = repository;
    }

    private LiveData<String> getPostalCode(String address) {
       // DON'T DO THIS
       return repository.getPostCode(address);
    }
}

For this reason:

If this is the implementation, the UI would need to unregister from the previous LiveData and re-register to the new instance each time they call getPostalCode(). Moreover, if the UI is re-created, it triggers another call to repository.getPostCode() instead of using the previous call’s result.

Is there a better way to get the ViewModel to "redo" its repo.getUsers() call? Perhaps I could just make a method that says "Update()" instead of "active" but still - its doing the same thing differently.

Upvotes: 1

Views: 1243

Answers (1)

NSimon
NSimon

Reputation: 5287

Well here you're doing the fetching in the creator of the ViewModel, which locks things in place. Usually they'd advise to fetch the data in the getter, if the data is not there already.

So a good option would be to use the regular pattern first :

  private MutableLiveData<Users> users = null;

 ViewModel(ViewModelRepo repo){
      this.repo = repo;
  }

   LiveData<Users> getUsers() {
    if (users = null) {
      fetchUsers();
    }
    return users;
  }

  public void fetchUsers() {
    users.postValue(repo.getUsers());
  }

And then from your Activity/Fragment, whenever you feel necessary to "refresh the users", you'd simply call viewModel.fetchUsers();

Upvotes: 3

Related Questions