关于LiveData多过滤条件实现及MediatorLiveData用法的咨询
Hey there! Let's work through your problem with combining multiple filters using LiveData—you're on the right track with MediatorLiveData, but there's a small tweak needed to make it work as expected.
1. 你的MediatorLiveData用法哪里出问题了?
Looking at your current code, the main issue is that when either name or category updates, you're only capturing the new value of the changed filter and grabbing the other filter's current value at that exact moment. This leads to two problems:
- If one filter hasn't been set yet (e.g.,
categoryis null whennamefirst updates), yourFilterobject will have a null value for that field. - Every time a single filter changes, you trigger a new API request immediately. So if you update
namethencategory, you get two requests instead of one combined request with both updated filters.
2. 修正后的MediatorLiveData实现
The fix is to track the latest value of each filter, and only emit a combined Filter object when we have valid values (or whenever you want to trigger a request, based on your business rules). Here's how to adjust your code:
class CustomLiveData extends MediatorLiveData<Filter> { // Track the latest values of each filter private String currentName; private String currentCategory; CustomLiveData(LiveData<String> name, LiveData<String> category) { // Initialize with initial values from the source LiveDatas currentName = name.getValue(); currentCategory = category.getValue(); // Observe name changes addSource(name, newName -> { currentName = newName; updateCombinedFilter(); }); // Observe category changes addSource(category, newCategory -> { currentCategory = newCategory; updateCombinedFilter(); }); } private void updateCombinedFilter() { // Here you can define when to trigger a filter update // Example 1: Only trigger if both filters are non-null (adjust based on your needs) if (currentName != null && currentCategory != null) { setValue(new Filter(currentName, currentCategory)); } // Example 2: Trigger even if some filters are null (let your repository handle empty filters) // setValue(new Filter(currentName, currentCategory)); } }
为什么这样有效?
- We keep track of the latest value for each filter in
currentNameandcurrentCategory. - Whenever either filter updates, we call
updateCombinedFilter()to create a singleFilterobject with both latest values. - You control when to emit the combined filter—whether that's only when all filters are present, or immediately whenever any filter changes (even with nulls).
3. 后续扩展到更多过滤条件
If you later add more filters (like a date range), you can easily extend this pattern:
- Add more
currentXvariables for each new filter. - Add an
addSource()call for each new filter's LiveData. - Update
updateCombinedFilter()to include all new filters in the emittedFilterobject.
4. 搭配switchMap完成API请求
Your existing switchMap setup will work perfectly with this corrected CustomLiveData:
CustomLiveData trigger = new CustomLiveData(name, category); return Transformations.switchMap(trigger, filter -> LiveDataReactiveStreams.fromPublisher( repository.getData(filter.getName(), filter.getCategory()) .toFlowable(BackpressureStrategy.BUFFER) ) );
Now, every time trigger emits a combined Filter, switchMap will cancel any ongoing API request and start a new one with the latest combined filters—exactly what you need!
总结
Your core idea of using MediatorLiveData to combine multiple filter LiveDatas is correct—you just missed tracking the latest values of all filters before emitting. With this adjustment, you can absolutely achieve your goal of combining multiple filters with ViewModel + LiveData, while retaining all the benefits you mentioned (avoiding updates to inactive views, surviving configuration changes).
内容的提问来源于stack exchange,提问作者unadivadantan

