首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多参数MediatorLiveData或switchMap变换

多参数MediatorLiveData或switchMap变换
EN

Stack Overflow用户
提问于 2018-03-26 14:23:38
回答 4查看 25.5K关注 0票数 51

我在我的ViewModel中使用ViewModel,所以我在片段中观察到的LiveData集合会对code参数的变化做出反应。

这是非常有效的:

代码语言:javascript
复制
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
    });
}

问题

现在我需要另一个参数(在上面的代码中注释了nbDays),这样我的LiveData对象就可以对两个参数的更改(codenbDays)做出反应。

我如何链式转换?

一些阅读指出了MediatorLiveData,但它并没有解决我的问题(仍然需要调用带有两个参数的单个DB函数,我不需要合并2 liveDatas)。

所以我尝试了这一点,而不是switchMap,但是codenbDays总是空的。

代码语言:javascript
复制
dayPrices.addSource(
    dbManager.getDayPriceData(code.getValue(), nbDays.getValue),
    apiResponse -> dayPrices.setValue(apiResponse)
);

一种解决方案是将一个对象作为单个参数传递给我,我确信这有一个简单的解决方案。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2018-03-30 19:05:46

来源:https://plus.google.com/+MichielPijnackerHordijk/posts/QGXF9gRomVi

要为switchMap()拥有多个触发器,您需要使用自定义MediatorLiveData来观察LiveData对象的组合-

代码语言:javascript
复制
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));
            }
        });
    }
}

然后你就能做到-

代码语言:javascript
复制
CustomLiveData trigger = new CustomLiveData(code, nbDays);
LiveData<DayPrices> dayPrices = Transformations.switchMap(trigger, 
    value -> dbManager.getDayPriceData(value.first, value.second));

如果您使用Kotlin并希望使用泛型:

代码语言:javascript
复制
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 }
    }
}

然后:

代码语言:javascript
复制
val dayPrices = Transformations.switchMap(DoubleTrigger(code, nbDays)) {
    dbManager.getDayPriceData(it.first, it.second)
}
票数 70
EN

Stack Overflow用户

发布于 2018-04-16 18:37:03

@jL4 4建议的自定义MediatorLiveData工作得很好,很可能是解决方案。

我只想分享我认为最简单的解决方案,就是使用内部类来表示组合的过滤器值:

代码语言:javascript
复制
public class MyViewModel extends AndroidViewModel {

    private final LiveData<DayPrices> dayPrices;
    private final DBManager dbManager;
    private final MutableLiveData<DayPriceFilter> dayPriceFilter;

    public MyViewModel(Application application) {
        super(application);
        dbManager = new DBManager(application.getApplicationContext());
        dayPriceFilter = new MutableLiveData<>();
        dayPrices = Transformations.switchMap(dayPriceFilter, input -> dbManager.getDayPriceData(input.code, input.nbDays));
    }

    public LiveData<DayPrices> getDayPrices() {
        return dayPrices;
    }

    public void setDayPriceFilter(String code, int nbDays) {
        DayPriceFilter update = new DayPriceFilter(code, nbDays);
        if (Objects.equals(dayPriceFilter.getValue(), update)) {
            return;
        }
        dayPriceFilter.setValue(update);
    }

    static class DayPriceFilter {
        final String code;
        final int nbDays;

        DayPriceFilter(String code, int nbDays) {
            this.code = code == null ? null : code.trim();
            this.nbDays = nbDays;
        }
    }

}

然后在活动/片段中:

代码语言:javascript
复制
public class MyFragment extends Fragment {

    private MyViewModel myViewModel;

    myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
    myViewModel.setDayPriceFilter("SO", 365);
    myViewModel.getDayPrices().observe(MyFragment.this, dataList -> {
        // update UI with data from dataList
    });
}
票数 24
EN

Stack Overflow用户

发布于 2020-03-24 11:01:00

简化了jL4的答案,(也在Kotlin中,以防对任何人有帮助).不需要为此创建自定义类:

代码语言:javascript
复制
class YourViewModel: ViewModel() {

    val firstLiveData: LiveData<String> // or whatever type
    val secondLiveData: LiveData<Int> // or whatever

    // the Pair values are nullable as getting "liveData.value" can be null
    val combinedValues = MediatorLiveData<Pair<String?, Int?>>().apply {
        addSource(firstLiveData) { 
           value = Pair(it, secondLiveData.value)
        }
        addSource(secondLiveData) { 
           value = Pair(firstLiveData.value, it)
        }
    }

    val results = Transformations.switchMap(combinedValues) { pair ->
      val firstValue = pair.first
      val secondValue = pair.second
      if (firstValue != null && secondValue != null) {
         yourDataSource.yourLiveDataCall(firstValue, secondValue)
      } else null
    }

}

解释

firstLiveDatasecondLiveData中的任何更新都将更新combinedValues的值,并将这两个值作为一对发出(这要感谢jL4 )。

调用liveData.value可以为null,因此此解决方案使成对的值可为空,以避免空指针异常。

因此,对于实际的结果/数据源调用,开关映射位于combinedValues活动数据上,从Pair中提取两个值并执行空检查,这样就可以确保将非空值传递给数据源。

票数 22
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49493772

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档