I'm trying to figure out MVVM (It's very new for me) and I figured out how to observe LiveData using Room and ViewModel. Now I am facing a problem.
I have a Room query which requires parameter and this is how I start observing the LiveData in onCreate in MainActivity.
String color = "red";
myViewModel.getAllCars(color).observe(this, new Observer<List<Car>>() {
@Override
public void onChanged(@Nullable List<Car> cars) {
adapter.setCars(cars);
}
});
By using this code, I recieve list of "red" cars and populate RecyclerView with the List.
Now to my question - is there a way to change the color
variable inside the getAllCars
method (for example by button click) and affect the observer to return new List? If i simply change the color variable, nothing happens.
As stated in this answer, your solution is Transformation.switchMap
From Android for Developers website:
LiveData< Y > switchMap (LiveData< X > trigger, Function< X, LiveData< Y >> func)
Creates a LiveData, let's name it swLiveData, which follows next flow: it reacts on changes of trigger LiveData, applies the given function to new value of trigger LiveData and sets resulting LiveData as a "backing" LiveData to swLiveData. "Backing" LiveData means, that all events emitted by it will retransmitted by swLiveData.
In your situation, it would look something like this:
public class CarsViewModel extends ViewModel {
private CarRepository mCarRepository;
private LiveData<List<Car>> mAllCars;
private LiveData<List<Car>> mCarsFilteredByColor;
private MutableLiveData<String> filterColor = new MutableLiveData<String>();
public CarsViewModel (CarRepository carRepository) {
super(application);
mCarRepository= carRepository;
mAllCars = mCarRepository.getAllCars();
mCarsFilteredByColor = Transformations.switchMap(
filterColor,
color -> mCarRepository.getCarsByColor(color)
);
}
LiveData<List<Car>>> getAllCars() { return mAllCars; }
LiveData<List<Car>> getCarsFilteredByColor() { return mCarsFilteredByColor; }
// When you call this function to set a different color, it triggers the new search
void setFilter(String color) { filterColor.setValue(color); }
}
So when you call the setFilter
method from your view, changing the filterColor LiveData will triger the Transformation.switchMap, which will call mRepository.getCarsByColor(c))
and then update with the query's result the mCarsFilteredByColor LiveData. Hence, if you are observing this list in your view and you set a different color, the observer receive the new data.
Other than @dglozano answer, one easy way to do this is to observe the color
instead of observing the list
. And on valueChange
of color
, fetch new list.
Example:
In ViewModel
class do this
MutableLiveData<String> myColor = new MutableLiveData<String>();
In Activity
do this:
button.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
myViewModel.myColor.setValue("newColor");
} });
myViewModel.myColor.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String newValue) {
// do this on dedicated thread
List<Car> updateList = myViewModel.getCarsByColor(newValue)
// update the RecyclerView
}
});
Note: 1.The getCarsByColor()
need not to be wrapped as LiveData
. The method in Dao
can return List<Cars>
instead of LiveData<List<Cars>>
.
2.Don't run the db queries on main thread, and do call the notifyDataSetChanged
to refresh the RecyclerView.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With