I am using Transformations.switchMap
in my ViewModel so my LiveData
collection, observed in my fragment, reacts on changes of code
parameter.
This works perfectly :
public class MyViewModel extends AndroidViewModel {
private final LiveData<DayPrices> dayPrices;
private final MutableLiveData<String> code = new MutableLiveData<>();
// private final MutableLiveData<Integer> nbDays = new MutableLiveData<>();
private final DBManager dbManager;
public MyViewModel(Application application) {
super(application);
dbManager = new DBManager(application.getApplicationContext());
dayPrices = Transformations.switchMap(
code,
value -> dbManager.getDayPriceData(value/*, nbDays*/)
);
}
public LiveData<DayPrices> getDayPrices() {
return dayPrices;
}
public void setCode(String code) {
this.code.setValue(code);
}
/*public void setNbDays(int nbDays) {
this.nbDays.setValue(nbDays);
}*/
}
public class MyFragment extends Fragment {
private MyViewModel myViewModel;
myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
myViewModel.setCode("SO");
//myViewModel.setNbDays(30);
myViewModel.getDayPrices().observe(MyFragment.this, dataList -> {
// update UI with data from dataList
});
}
Problem
I now need another parameter (nbDays
commented in the code above), so that my LiveData
object reacts on both parameters change (code
and nbDays
).
How can I chain transformations ?
Some reading pointed me to MediatorLiveData, but it does not solve my problem (still need to call single DB function with 2 parameters, I don't need to merge 2 liveDatas).
So I tried this instead of switchMap
but code
and nbDays
are always null.
dayPrices.addSource(
dbManager.getDayPriceData(code.getValue(), nbDays.getValue),
apiResponse -> dayPrices.setValue(apiResponse)
);
One solution would be to pass an object as single parameter by I'm pretty sure there is a simple solution to this.
Source : https://plus.google.com/+MichielPijnackerHordijk/posts/QGXF9gRomVi
To have multiple triggers for switchMap()
, you need to use a custom MediatorLiveData
to observe the combination of the LiveData objects -
class CustomLiveData extends MediatorLiveData<Pair<String, Integer>> {
public CustomLiveData(LiveData<String> code, LiveData<Integer> nbDays) {
addSource(code, new Observer<String>() {
public void onChanged(@Nullable String first) {
setValue(Pair.create(first, nbDays.getValue()));
}
});
addSource(nbDays, new Observer<Integer>() {
public void onChanged(@Nullable Integer second) {
setValue(Pair.create(code.getValue(), second));
}
});
}
}
Then you can do this -
CustomLiveData trigger = new CustomLiveData(code, nbDays);
LiveData<DayPrices> dayPrices = Transformations.switchMap(trigger,
value -> dbManager.getDayPriceData(value.first, value.second));
If you use Kotlin and want to work with generics:
class DoubleTrigger<A, B>(a: LiveData<A>, b: LiveData<B>) : MediatorLiveData<Pair<A?, B?>>() {
init {
addSource(a) { value = it to b.value }
addSource(b) { value = a.value to it }
}
}
Then:
val dayPrices = Transformations.switchMap(DoubleTrigger(code, nbDays)) {
dbManager.getDayPriceData(it.first, it.second)
}