Как настроить LiveData для выполнения поиска по нескольким параметрам? - PullRequest
1 голос
/ 09 мая 2019

У меня есть настройка моего приложения с использованием архитектуры MVVM. Проблема, которую я пытаюсь решить, состоит в том, чтобы инициировать вызов API на основе двух параметров запроса (в данном случае, источника и назначения), причем это происходит динамически и обновляется в реальном времени. Когда любое из этих значений обновляется, следует проверить, что оба значения не равны NULL, а затем сделать вызов API, основываясь на этих двух значениях.

Я играл с MediatorLiveData и Transformations.switchMap(), но не смог найти решение, которое работает хорошо. Попытка с использованием MediatorLiveData:

class MyViewModel(val repository: AppRepository) : ViewModel() {

  val origin = MutableLiveData<Location>()
  val destination = MutableLiveData<Location>()

  val directions = MediatorLiveData<DrivingDirections>()

  init {
    directions.addSource(origin) { origin ->
       if (origin != null && destination.value != null) {
          directions.value = // problem here
          // I want to make a call to something like 
          // repository.getDirections(origin, destination), but this comes
          // back as LiveData<Directions> so *can't* set it to directions.value
          // I, in effect, want to make directions = repository.getDirections(origin, destination),
          // but then I lose the Mediator functionality
       }
    }
    directions.addSource(destination) {
      // as above
    }
  }

}

Итак, пытаясь использовать switchMap, я создал сырой OriginAndDestination объект, а затем заметил изменения в нем.

class myViewModel(val repository: AppRepository) : ViewModel() {

  val originAndDestination = MutableLiveData<OriginAndDestination>()
  val directions: LiveData<Directions>

  init {
    directions = Transformations.switchMap(originAndDestination) { originAndDestination -> 
    // probably should do some checks that both origin and destination are not null, 
    // so this switch map could return null? How do I guard against null in a switch map?

      repository.getDirections(originAndDestination.origin, originAndDestination.destination)
    }
  }

  fun setOrigin(location: Location) {
    // bit of problem code here... need to retrieve the current value of 
    // originAndDestination.value, then update the 'origin' property,
    // then set it to the liveData value again to trigger the switchMap, above... while checking that the value isn't null in the first place...
    //  something like:
    val tempValue = originAndDestination.value
    if (tempValue != null) {
      // update tempValue.origin
    } else {
      // create a new OriginAndDestination object?
    }
    // just feels really messy
  }

  fun setDestination(location: Location) {
    // As above
  }

}

Извините за все комментарии, но он подчеркивает некоторые болевые точки и разочарования. Я иду по этому пути все неправильно? Origin и Destination устанавливаются из полей пользовательского интерфейса.

1 Ответ

1 голос
/ 09 мая 2019

Это больше MVI, чем MVVM, но я бы подошел к нему так:

data class myViewState(
  val origin: Location,
  val destination: Location,
  val directions: DrivingDirections
)

class myViewModel(val repository: AppRepository) : ViewModel() {
  private val _states = MediatorLiveData<myViewState>()
  val states: LiveData<myViewState> = _states
  private val lastSource: LiveData<myViewState>? = null

  fun updateLocations(origin: Location, destination: Location) {
    lastSource?.let { _states.removeSource(lastSource) }
    lastSource = repository.getDirections(origin, destination)

    _states.addSource(lastSource) { directions ->
      _states.value = myViewState(origin, destination, directions)
    }
  }
}

(где, если повезет, мы можем избавиться от lastSource когда-нибудь в будущем )

Затем ваш уровень пользовательского интерфейса наблюдает за states и обновляет свой пользовательский интерфейс для местоположений и направлений.

Это может не соответствовать вашей архитектуре, но может дать вам некоторые идеи.

...