LiveData с фильтрами? - PullRequest
4 голосов
/ 09 мая 2020

Я новичок в LiveData и в последнее время проводил несколько тестов. У меня есть приложение, в котором мне нужно отображать данные, которые можно фильтровать (имя, категория, дата ...). Фильтры тоже можно комбинировать (имя + дата). Эти данные поступают из вызова API с помощью Retrofit + RX Java.

Я знаю, что могу иметь данные прямо в моем представлении без использования 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?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 14 мая 2020

Как вы это устанавливаете в своем ответе, каждый раз, когда вы звоните updateData(), вы будете добавлять новый источник в свой MediatorLiveData. Вам нужны разные источники каждый раз, когда изменяются новые name и category?

Кроме того, не могли бы вы использовать метод репозитория getData для прямого доступа к LiveData? И, наконец, можно ли использовать Kotlin вместо Java?

Если да, то вы можете упростить свой поток, условно проверив onChanged каждого источника, когда устанавливать значение в вашем data MediatorLiveData.

Например, следуя документации здесь :

//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) {
                if (filter(it)) {
                    this.value = it
                }
            }
        }
    }

Затем в вашем методе updateData() вы можете сделать:

val data = repository.getData(name, category)
    .filter { value ->
        // Your boolean expression to validate the values to return
    }
0 голосов
/ 09 мая 2020

Мне кажется, я смотрел на проблему под неправильным углом. Поправьте меня, если я ошибаюсь, пожалуйста.

Я пытался обновить LiveData на основе изменений других LiveDatas, когда я мог обновить свои 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 выполняются только один раз с этим решением, и у меня могут быть оба фильтра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...