Search code examples
androidandroid-roomandroid-architecture-components

change the query parameter of android view model on the basis of preference change listener


I am using architecture component in my application. I have used paging but I have a problem that how to re-query the db if parameter gets changed on the basis of preferences. Because view model is setup in oncreate method and it we call a query on Dao interface inside view model constructor.

I tried to recreate the view model inside onPreferenceChangeLitener but its not working.

My main activity is as-

public class MainActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener{

    private static final String TAG = MainActivity.class.getSimpleName();

    RecyclerView rvDisplayMovie;
    MovieAdapter mAdapter;

    MainActivityViewModel mViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rvDisplayMovie = (RecyclerView) findViewById(R.id.rv_display_movies);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        rvDisplayMovie.setLayoutManager(linearLayoutManager);
        mAdapter = new MovieAdapter();

        rvDisplayMovie.setAdapter(mAdapter);

        MainViewModelFactory factory = InjectorUtils.provideMainViewModelFactory(this);

        mViewModel = ViewModelProviders.of(this, factory).get(MainActivityViewModel.class);

        mViewModel.getMovies().observe(this, new Observer<PagedList<MovieEntry>>() {
            @Override
            public void onChanged(@Nullable PagedList<MovieEntry> movieEntries) {
                Log.d(TAG,"Movie list changed"+movieEntries.size());
                mAdapter.submitList(movieEntries);
            }
        });

        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPreferences.registerOnSharedPreferenceChangeListener(this);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main_settings,menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_settings:
                Intent intent = new Intent(this, SettingsActivity.class);
                startActivity(intent);
                return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
        mViewModel.triggerPrefsChenged(this);
    }
}

and view model is-

public class MainActivityViewModel extends ViewModel {

    private static final String TAG = MainActivityViewModel.class.getSimpleName();

    private PopularMovieRepository mRepository;
    private LiveData<PagedList<MovieEntry>> mMovies;

    public MainActivityViewModel(PopularMovieRepository repository, int movieType){
        mRepository = repository;
        mMovies = mRepository.getMoviesList(movieType);
    }

    public  LiveData<PagedList<MovieEntry>> getMovies() {
        return mMovies;
    }

    public void triggerPrefsChenged(Context context){
        int movieType = PreferenceUtils.getMovieType(context);
        mRepository.initializeData(movieType);
    }
}

triggerPrefsChenged method downloads new data and insert it in to database


Solution

  • A problem with your approach is that your mMovies is hardcoded for the initial movieType (the one you pass in MainActivityViewModel). You should modify your mMovies usage so that it could react to movieType changes.

    A good way to do this is to create an additional LiveData object that listens to movieType changes and then triggers mRepository.getMoviesList(movieType) call with the new type using Transformations.switchMap. So, your ViewModel could be as follows:

    public class MainActivityViewModel extends ViewModel {
    
        private static final String TAG = MainActivityViewModel.class.getSimpleName();
        private PopularMovieRepository mRepository;
        private final MutableLiveData<Integer> mMovieTypeLiveData = new MutableLiveData();
        private final LiveData<PagedList<MovieEntry>> mMovies;
    
        public MainActivityViewModel(PopularMovieRepository repository, int movieType){
            mRepository = repository;
            mMovies = Transformations.switchMap(movieTypeLive, (movieType) -> {
                return mRepository.getMoviesList(movieType);
            });
            //set the initial value
            mMovieTypeLiveData.setValue(movieType);
        }
    
        public LiveData<PagedList<MovieEntry>> getMovies() {
            return mMovies;
        }
    
        public void triggerPrefsChenged(Context context){
            int movieType = PreferenceUtils.getMovieType(context);
            //mRepository.initializeData(movieType);
            mMovieTypeLiveData.setValue(movieType);
        }
    }