ViewModel - изменить параметр метода при наблюдении за LiveData во время выполнения?

Я пытаюсь понять MVVM (это очень ново для меня), и я понял, как наблюдать за LiveData с помощью Room и ViewModel. Теперь я столкнулся с проблемой.

У меня есть запрос Room, для которого требуется параметр, и именно так я начинаю наблюдать за LiveData в onCreate в MainActivity.

    String color = "red";
    myViewModel.getAllCars(color).observe(this, new Observer<List<Car>>() {
            @Override
            public void onChanged(@Nullable List<Car> cars) {
                adapter.setCars(cars);
            }
        });

Используя этот код, я получаю список «красных» автомобилей и заполняю RecyclerView списком.

Теперь к моему вопросу - есть ли способ изменить переменную color внутри метода getAllCars (например, нажатием кнопки) и повлиять на наблюдателя, чтобы он возвращал новый список? Если я просто изменю цветовую переменную, ничего не произойдет.

6
0
2 328
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Как указано в этом ответе, ваше решение - Transformation.switchMap

От Сайт Android для разработчиков:

LiveData< Y > switchMap (LiveData< X > trigger, Function< X, LiveData< Y >> func)

Creates a LiveData, let's name it swLiveData, which follows next flow: it reacts on changes of trigger LiveData, applies the given function to new value of trigger LiveData and sets resulting LiveData as a "backing" LiveData to swLiveData. "Backing" LiveData means, that all events emitted by it will retransmitted by swLiveData.

В вашей ситуации это будет выглядеть примерно так:

public class CarsViewModel extends ViewModel {
    private CarRepository mCarRepository;
    private LiveData<List<Car>> mAllCars;
    private LiveData<List<Car>> mCarsFilteredByColor;
    private MutableLiveData<String> filterColor = new MutableLiveData<String>();
    
    public CarsViewModel (CarRepository carRepository) {
        super(application);
        mCarRepository= carRepository;
        mAllCars = mCarRepository.getAllCars();
        mCarsFilteredByColor = Transformations.switchMap(
            filterColor,
            color -> mCarRepository.getCarsByColor(color)
        );
    }
    
    LiveData<List<Car>>> getAllCars() { return mAllCars; }
    LiveData<List<Car>> getCarsFilteredByColor() { return mCarsFilteredByColor; }

    // When you call this function to set a different color, it triggers the new search
    void setFilter(String color) { filterColor.setValue(color); }
}

Поэтому, когда вы вызываете метод setFilter из своего представления, изменение filterColor LiveData запускает Transformation.switchMap, который вызывает mRepository.getCarsByColor(c)), а затем обновляет результат запроса mCarsFilteredByColor LiveData. Следовательно, если вы наблюдаете этот список в своем представлении и устанавливаете другой цвет, наблюдатель получит новые данные.

это было полезно для меня, когда мне приходилось извлекать данные из комнаты на основе различных вариантов сортировки, выбранных пользователем. Раньше я делал это очень необычным способом. Спасибо!

Shahood ul Hassan 10.02.2019 07:58

Ваш код очень помог. Но есть проблема в строке: private LiveData<String> filterColor = new MutableLiveData<String>(); вместо private MutableLiveData<String> filterColor = new MutableLiveData<String>();, потому что LiveData'ssetValue() имеет защищенный доступ, а MutableLiveData'ssetValue() имеет открытый доступ.

Sayok Majumder 31.05.2019 09:53

@SayokMajumder ты прав, спасибо! Ответ отредактирован.

dglozano 31.05.2019 15:16

Помимо ответа @dglozano, один простой способ сделать это - наблюдать за color вместо наблюдения за list. И на valueChange из color получите новый список.

Пример:

В классе ViewModel сделайте это

MutableLiveData<String> myColor = new MutableLiveData<String>();

В Activity сделайте так:

button.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
    myViewModel.myColor.setValue("newColor");
} });

myViewModel.myColor.observe(this, new Observer<String>() {
        @Override
        public void onChanged(@Nullable String newValue) {
           // do this on dedicated thread
           List<Car> updateList = myViewModel.getCarsByColor(newValue)
           // update the RecyclerView
        }
    });

Примечание: 1. getCarsByColor() не нужно упаковывать как LiveData. Метод в Dao может возвращать List<Cars> вместо LiveData<List<Cars>>.

2. Не запускайте запросы к базе данных в основном потоке и вызывайте notifyDataSetChanged, чтобы обновить RecyclerView.

Не знаю, чего ты здесь пытаешься достичь. Почему вам нужно использовать наблюдателя для «наблюдения» за цветом, если вы уже знаете об изменении его значения с помощью метода onClick? В некотором смысле вы сами устанавливаете значение, а затем получаете то же самое через наблюдателя, что бессмысленно.

Shahood ul Hassan 10.02.2019 08:04

Другие вопросы по теме