Search code examples
androidandroid-fragmentsviewmodel

How to update Viewmodels fragments in MainActivity?


I have 3 same fragments in a ViewPager that each contain a ViewModel where I observe for changes on the fragment whenever the list is changed.

Here's the observer;

    mReleasesViewModel = ViewModelProviders.of(this, new ReleasesViewModelFactory(filter)).get(ReleasesViewModel.class);
    // livedata
    mDatabaseLoading.setVisibility(View.VISIBLE);
    mReleasesViewModel.getUpcomingReleases().observe(this, new Observer<List<_Release>>() {
        @Override
        public void onChanged(@Nullable List<_Release> releases) {
            // whenever the list is changed
            if (releases != null) {
                mUpcomingGamesAdapter.setData(releases);
                mUpcomingGamesAdapter.notifyDataSetChanged();
            }
            mDatabaseLoading.setVisibility(View.GONE);
        }
    }); 

Now in the MainActivity there's a drawer that contains platforms to filter from e.g PC, Xbox and PS4, and when the user closes the drawer I want all of my 3 fragments to update gracefully, is this possible to accomplish with viewmodel? Like how can I observer for list changes and for platforms changes? The drawer in Main Activity adds the selected platforms to a list of Integer e.g PS4 has id of 3

My ViewModel:

public class ReleasesViewModel extends ViewModel {
    public static final String TAG = ViewModel.class.getSimpleName();
    // Example: Whenever the value contained by this MutableLiveData changes, we will set the contained value to our TextView
    // Livedata objects will usually be kept in the ViewModel class
    private MutableLiveData<List<_Release>> upcomingReleases;
    // this field [mMonthYearFilter] is passed by our fragment to the AndroidViewModel
    // to pass additional argument to my custom AndroidViewModel I need a AndroidViewModelFactory
    private String monthYearFilter;
    private ReleasesRepository releasesRepository;

    public ReleasesViewModel(String monthYearFilter) {
        this.monthYearFilter = monthYearFilter;
    }

    public MutableLiveData<List<_Release>> getUpcomingReleases() {
        if (upcomingReleases == null) {

            upcomingReleases = new MutableLiveData<>();

            // User settings region & platforms
            String region = SharedPrefManager.read(SharedPrefManager.KEY_PREF_REGION, "North America");
            Set<String> defaultPlatformsSet = new HashSet<>();
            ArrayList<Integer> platforms = SharedPrefManager.read(SharedPrefManager.PLATFORM_IDS, defaultPlatformsSet);

            releasesRepository = new ReleasesRepository(region, monthYearFilter, platforms);
            loadReleases();
        }
        return upcomingReleases;
    }


    private void loadReleases() {
        releasesRepository.addListener(new FirebaseDatabaseRepository.FirebaseDatabaseRepositoryCallback<_Release>() {
            @Override
            public void onSuccess(List<_Release> result) {
                upcomingReleases.setValue(result);
            }

            @Override
            public void onError(Exception e) {
                Log.e(TAG, e.getMessage());
                upcomingReleases.setValue(null);
            }
        });
    }
}

Solution

  • Have only 1 ViewModel created at an Activity level and pass it to your fragments. Your ViewModel can have 3 LiveData serving for each of your fragments. let's assume you are showing upcoming releases in one fragment and already released games in another. So just like you did for upcoming releases, create another method in your ViewModel and return a LiveData which will hold the list of released games.

    In the below code mViewModel will be the passed view model to your fragments.

    mViewModel.getReleasedGames().observe(this, new Observer<List<_Release>>() {
            @Override
            public void onChanged(@Nullable List<_Release> released_games) {
                // whenever the list is changed
                if (released_games != null) {
                    mReleasedGamesAdapter.setData(releases);
                    mReleasedGamesAdapter.notifyDataSetChanged();
                }
                mDatabaseLoading.setVisibility(View.GONE);
            }
        });