android - 如何设置 LiveData 以根据多个参数执行搜索?

标签 android android-livedata android-viewmodel

我使用 MVVM 架构设置我的应用程序。我要解决的问题是根据两个查询参数(在本例中为起点和终点)触发 api 调用,这是动态的并实时更新。当更新这些值中的任何一个时,应检查两者都不为空,然后根据这两个值进行 api 调用。

我一直在使用 MediatorLiveDataTransformations.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
  }

}

对所有评论表示抱歉,但它突出了一些痛点和挫败感。我会以错误的方式处理这件事吗? OriginDestination 从 UI 字段设置。

最佳答案

这比 MVVM 更像是 MVI,但这是我处理它的方式:

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 sometime in the future )

然后,您的 UI 层会观察状态,并根据位置和方向更新其 UI。

这可能不适合您的架构,但它可能会给您一些想法。

关于android - 如何设置 LiveData 以根据多个参数执行搜索?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56059225/

相关文章:

Android SwitchCompat 在 toggle() 或 setChecked() 上播放动画

android - 三个不同设计的CardView只能用一个RecyclerView吗?

android - 当 View 模型中更新另一个 LiveData 时触发 LiveData 成员的更新

android - BaseFragment中的LiveData使用者未从BaseViewModel接收更新

java - 使用 RxJava 将数据从 ViewModel 移动到 Fragment

android - 使用 Android 共享首选项来存储大量数据是个好主意吗?

android - ViewModelFactory can't create an instance 错误创建自定义ViewModelFactory类

android - Koin - 如何为 Espresso 测试提供模拟 ViewModel?

java - 使用 Retrofit 请求响应刷新实时数据

Android Studio 内置的 Android Wear apk 在“手机”上打开时不会解析