4

我是 LiveData 的新手,最近我一直在做一些测试。我有一个应用程序,我需要在其中显示可以过滤的数据(名称、类别、日期......)。过滤器也可以组合(名称+日期)。该数据来自使用 Retrofit + RXJava 的 API 调用。

我知道我可以在不使用 LiveData 的情况下直接在我的视图中获取数据。但是,我认为使用 ViewModel + LiveData 会很有趣。首先,要测试它是如何工作的,还要避免在视图不活动时尝试设置数据(感谢 LiveData)并在配置更改时保存数据(感谢 ViewModel)。这些是我以前必须手动处理的事情。

所以问题是我没有找到一种方法来使用 LiveData 轻松处理过滤器。在用户选择一个过滤器的情况下,我设法使其与 switchMap 一起工作:

return Transformations.switchMap(filter,
    filter -> LiveDataReactiveStreams.fromPublisher(
    repository.getData(filter).toFlowable(BackpressureStrategy.BUFFER)));

如果他选择两个过滤器,我发现我可以使用自定义 MediatorLiveData,这就是我所做的。但是,这里的问题是我的存储库调用与我拥有的过滤器数量一样多,而且我不能同时设置两个过滤器

我的自定义 MediatorLiveData:

class CustomLiveData extends MediatorLiveData<Filter> {

    CustomLiveData(LiveData<String> name, LiveData<String> category) {
        addSource(name, name -> {
            setValue(new Filter(name, category.getValue()));
        });

        addSource(category, category -> {
            setValue(new Filter(name.getValue(), newCategory));
        });
    }
}
CustomLiveData trigger = new CustomLiveData(name, category);

  return Transformations.switchMap(trigger,
     filter -> LiveDataReactiveStreams.fromPublisher(
        repository.getData(filter.getName(), filter.getCategory())
        .toFlowable(BackpressureStrategy.BUFFER)));

我是否充分了解 MediatorLiveData 的用法?是否可以使用 LiveData 实现我想要实现的目标?

谢谢!

4

2 回答 2

4

您在答案中设置的方式,每次您打电话updateData()时都会向您的MediatorLiveData. 每次新的namecategory更改时,您是否需要不同的来源?

另外,您可以让您的存储库方法直接getData公开一个吗?LiveData最后,是否可以使用 Kotlin 代替 Java?

如果是这样,您可以通过有条件地检查onChanged每个源的 何时在dataMediatorLiveData 中设置值来简化流程。

例如,按照此处的文档:

//Create a new instance of MediatorLiveData if you don't need to maintain the old sources
val data = MediatorLiveData<List<Data>>().apply {
    addSource(repository.getData(name, category)) { value ->
        if (yourFilterHere) {
            this.value = value
        }
    }
}

你也可以扩展这个想法,用 Kotlin 创建一个扩展函数:

inline fun <T> LiveData<T>.filter(crossinline filter: (T?) -> Boolean): LiveData<T> {
        return MediatorLiveData<T>().apply {
            addSource(this@filter) {
                if (filter(it)) {
                    this.value = it
                }
            }
        }
    }

然后,在您的updateData()方法中,您可以执行以下操作:

val data = repository.getData(name, category)
    .filter { value ->
        // Your boolean expression to validate the values to return
    }
于 2020-05-14T20:24:42.977 回答
0

我认为我从错误的角度看待问题。如果我错了,请纠正我。

当我可以直接更新我的 LiveData 时,我试图根据其他 LiveData 的更改来更新 LiveData。我找到的解决方案是拥有一个由视图直接更新的 MediatorLiveData。它可能是 MutableLiveData 但由于我使用的是 LiveDataReactiveStreams 并且它不接受 MutableLiveData 我没有找到其他解决方案。

public class MainViewModel extends AndroidViewModel {

    // Had to use a MediatorLiveData because the LiveDataReactiveStreams does not accept a MutableLiveData
    private MediatorLiveData<List<Data>> data = new MediatorLiveData<>();

    public MainViewModel(@NonNull Application application) {
        super(application);

        data.addSource(
            LiveDataReactiveStreams.fromPublisher(
                repository.getData(name, category)
                    .toFlowable(BackpressureStrategy.BUFFER)
            ), value -> data.setValue(value));
    }

    public LiveData<List<Data>> getData() {
        return data;
    }

    public void updateData(String name, String category) {
        data.addSource(
            LiveDataReactiveStreams.fromPublisher(
                repository.getData(name, category)
                    .toFlowable(BackpressureStrategy.BUFFER)
            ), value -> data.setValue(value));
    }
}

然后在活动中,我只是这样称呼它:

viewModel.updateData(name, category);

我不知道在尝试添加另一个源之前是否应该删除一个源,但我的 API 调用只用这个解决方案完成一次,我可以同时拥有两个过滤器。

于 2020-05-09T11:00:36.857 回答