为什么在调用ViewModel onCleared()方法后,ViewModelScoped协程不可用

问题描述 投票:0回答:2

我正在当前的Android应用程序中的多个片段之间共享一个ActivityScoped viewModel。

viewModel使用协程范围viewModelScope.launch{}

我的问题是,.launch{}仅在调用拥有的ViewModel onCleared()方法之前有效。

这是ViewModel范围的协程应该工作的方式吗?

是否有一种方法可以用来“重置” viewModelScope,以便.launch {}在调用onCleared()方法之后起作用?

这里是我的代码::

片段

RxSearchView.queryTextChangeEvents(search)
        .doOnSubscribe {
            compositeDisposable.add(it)
        }
        .throttleLast(300, TimeUnit.MILLISECONDS)
        .debounce(300, TimeUnit.MILLISECONDS)
        .map { event -> event.queryText().toString() }
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe { charactersResponse ->
            launch {
                viewModel.search(charactersResponse.trim())
            }
        }

。。。

override fun onDetach() {
    super.onDetach()
    viewModel.cancelSearch()
    compositeDisposable.clear()
}

ViewModel

suspend fun search(searchString: String) {
    cancelSearch()

    if (TextUtils.isEmpty(searchString)) {
        return
    }

    job = viewModelScope.launch {
        repository.search(searchString)
    }
}

fun cancelSearch() {
    job?.cancelChildren()
}

。。。

override fun onCleared() {
    super.onCleared()
    repository.onCleared()
 }

我在做什么错?

UPDATE

如果我将启动代码修改为此

job = GlobalScope.launch {
    repository.search(searchString)
}

它解决了我的问题,但是这是达到我期望的结果的唯一方法吗?

我对GlobalScope的印象是“不好”

android dagger-2 kotlin-coroutines android-viewmodel
2个回答
1
投票
repository.onCleared()

此方法不应属于存储库。

实际上,存储库不应是有状态的。

[如果您检查Google的样本the Repository creates a LiveData that contains a Resource,并且之所以有意义,是因为LiveData(在此样本中为Resource,但从语义上讲,这是同一件事)。

the actual data loading and caching mechanic is inside this resource, triggered by LiveData.onActive

片段不应该启动协同程序。它应该说类似

LiveData.onActive

还有

MediatorLiveData.addSource

然后使用ViewModel将>

    .subscribe { charactersResponse ->
        launch {
            viewModel.search(charactersResponse.trim())

这就是ViewModel中应该有的所有内容,那么问题是“谁拥有协程范围”?这取决于何时应取消任务。

如果“不再观察”应该取消任务,那么取消任务应该是.subscribe { viewModel.updateSearchText(charactersResponse.trim()) }

如果“不再观察但不再清除”应保留任务,则ViewModel的onCleared实际上应控制ViewModel内部的SupervisorJob,该工作将在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) }) } 中取消,并且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) } } 应该在该范围内启动,即仅当您将CoroutineScope传递给LiveData.onInactive()方法时,才有可能。

onCleared()

这项工作吗?不确定,我实际上并不使用协程,但我认为应该使用。但是,此示例不处理LiveData中的search -ing操作,也不处理协程。


2
投票

将cal设置为onCleared()之后,我的viewModelScoped cororoutine启动将停止执行

© www.soinside.com 2019 - 2024. All rights reserved.