repository.onCleared()
Этот метод не должен принадлежать хранилищу.
На самом деле хранилище не должно быть с состоянием.
Если вы проверяете образцы Google, Репозиторий создает LiveData
, который содержит Resource
, и причина, по которой это важно, заключается в том, что фактическая механика загрузки и кэширования данных находится внутри этого ресурса, вызванного LiveData.onActive
(в данном примере MediatorLiveData.addSource
, но технически это семантически одно и то же).
.subscribe { charactersResponse ->
launch {
viewModel.search(charactersResponse.trim())
Фрагмент не должен запускать сопрограммы. Он должен сказать что-то вроде
.subscribe {
viewModel.updateSearchText(charactersResponse.trim())
}
, а также
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java, factory)
viewModel.searchResults.observe(viewLifecycleOwner, Observer { results ->
searchAdapter.submitList(results)
})
}
Тогда ViewModel будет
class MyViewModel(
private val repository: MyRepository
): ViewModel() {
private val searchText = MutableLiveData<String>()
fun updateSearchText(searchText: String) {
this.searchText.value = searchText
}
val searchResults: LiveData<List<MyData>> = Transformations.switchMap(searchText) {
repository.search(searchText)
}
}
И это все, что должно быть в ViewModel, так что тогдавопрос "кому принадлежит область сопрограмм"? Это зависит от того, когда задача должна быть отменена.
Если «больше не наблюдается» отменяет задачу, то для отмены задачи должно быть LiveData.onInactive()
.
Если «больше не наблюдается»но не очищенный »должен сохранить задачу, тогда OnCleared ViewModel должен действительно управлять SupervisorJob внутри ViewModel, который будет отменен в onCleared()
, и search
должен быть запущен в этой области, что, вероятно, возможно только если вы передадитеCoroutineScope для search
метода.
suspend fun search(scope: CoroutineScope, searchText: String): LiveData<List<T>> =
scope.launch {
withContext(Dispatchers.IO) { // or network or something
val results = networkApi.fetchResults(searchText)
withContext(Dispatchers.MAIN) {
MutableLiveData<List<MyData>>().apply { // WARNING: this should probably be replaced with switchMap over the searchText
this.value = results
}
}
}
}
Будет ли это работать? Не уверен, я на самом деле не использую сопрограммы, но я думаю, что это должно. Этот пример, однако, не обрабатывает эквивалент switchMap
-ing внутри LiveData и сопрограмм.