如何处理以前的请求并停止观察以前的 LiveData
Posted
技术标签:
【中文标题】如何处理以前的请求并停止观察以前的 LiveData【英文标题】:How to dispose previous requests and stop observing the previous LiveData 【发布时间】:2020-04-11 00:11:49 【问题描述】:我正在尝试实现一个有 searchView 的应用程序,当用户搜索某些内容时,应用程序将调用一个返回可观察数据的改造请求。在 myRepository 中,我将 observable 转换为 flowable,在 myViewModel 中,我将 flowable 转换为我在 myActivity 中观察到的 LiveData。
但问题是,如果用户搜索不止一次并且非常快(在获得上一个结果之前),那么我想取消以前的请求并且也不想观察以前的数据。
所以我使用的代码如下:
MainActivity
class MainActivity : DaggerAppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
observeRepos()
fun getReposFromServer(filter_search :String )
mainViewModel.getReposFromServer(filter_search)
private fun observeRepos()
mainViewModel.observeReposFromServer().observe(this, Observer repos ->
txtVwCount.setText("total item count is: "+repos?.total_count.toString())
)
mainViewModel.observeItemList().observe(this, Observer
if(!it.isNullOrEmpty())
if(it.size>0)
mAdapter.setReposInAdapter(it)
progressBar.visibility = View.GONE
)
override fun onCreateOptionsMenu(menu: Menu?): Boolean
.....
......
searchView.setOnQueryTextListener(object: SearchView.OnQueryTextListener
override fun onQueryTextSubmit(query: String?): Boolean
query?.let
if(it.trim().length>0)
clearOldCalls()
getReposFromServer(it,"","")
return false
override fun onQueryTextChange(newText: String?): Boolean
return false;
)
return true
fun clearOldCalls()
mainViewModel.clearRetrofitCall()
mAdapter.clearListInAdapter() //in my adapter I just make the list empty by assigning a new list to it
MainViewModel:
class MainViewModel @Inject constructor() : ViewModel()
var liveGitResult = MediatorLiveData<GitResult>()
val liveItemList = MediatorLiveData<MutableList<ItemList>>()
@set:Inject
lateinit var mainRepository: MainRepository
fun getReposFromServer(filter_search: String)
val resultFromApiCall_flowable : Flowable<GitResult> = mainRepository.fetchToDosFromServer(filter_search)
lateinit var source: LiveData<GitResult>
resultFromApiCall_flowable.let
source = LiveDataReactiveStreams.fromPublisher(it)
liveGitResult.addSource(source) todos ->
liveGitResult.setValue(todos)
liveGitResult.removeSource(source)
var itemList_observable = resultFromApiCall_flowable.map //it = gitResult
gitResult ->
var lst = mutableListOf<ItemList>()
gitResult.items.forEach
lst.add(it)
lst
itemList_observable?.let
var liveItemList = LiveDataReactiveStreams.fromPublisher(itemList_observable)
this.liveItemList.addSource(liveItemList) itemList ->
this.liveItemList.setValue(itemList)
this.liveItemList.removeSource(liveItemList)
fun observeReposFromServer(): LiveData<GitResult>
return liveGitResult
fun observeItemList(): LiveData<MutableList<ItemList>>
return liveItemList
fun clearRetrofitCall()
liveGitResult.value =null
liveItemList.value = null
mainRepository.clearDisposables()
MainRepository:
class MainRepository @Inject constructor(mainApi: MainApi)
private val mainApi: MainApi
private val disposables: CompositeDisposable = CompositeDisposable()
init
this.mainApi = mainApi
fun fetchToDosFromServer(filter_search: String) : Observable<GitResult>
lateinit var returnedData : Observable<GitResult>
//mainApi.getAllRepo(filter_search) is a retrofit call which returns a Flowable<GitResult>
returnedData = mainApi.getAllRepo(filter_search).subscribeOn( Schedulers.io())
.onErrorReturn(Function throwable ->
Log.e( LOG_TAG, "Something went wrong" )
null
)
returnedData.subscribeOn(Schedulers.io())
.observeOn( androidSchedulers.mainThread())
.subscribe(object :Observer<GitResult>
override fun onSubscribe(d: Disposable)
disposables.add(d)
override fun onComplete()
override fun onNext(t: GitResult)
override fun onError(e: Throwable)
)
return returnedData.toFlowable(BackpressureStrategy.BUFFER);
fun clearDisposables()
if(disposables!=null)
if(!disposables.isDisposed)
disposables.clear()
disposables.dispose()
现在,如果我在获得上一个结果之前运行应用程序并快速搜索多次 - 那么它的行为很奇怪..
它在recyclerview 中一一显示所有结果。之前的结果不应该被处理掉并且不会转换为 liveData 吗? 也不是按顺序调用它们 此外,没有同时显示 recyclerview 数据和 textView 数据,可能使用来自不同 Livedata 源的观察者那么,我哪里做错了?
还有如何在单个语句中编写 returnedData
的代码,而不是在我正在执行的 2 个语句中编写它(一个用于调用 api,另一个用于覆盖订阅方法)。 p>
【问题讨论】:
【参考方案1】:对于类似的情况,我会保留一堆一次性用品,并在开始新订阅时处理最旧的订阅。我在其中运行 OkHtttp 请求,所以在处理时,它们被中断了。
【讨论】:
【参考方案2】:当用户创建另一个请求而前一个请求仍在进行中时,要取消以前的改造请求,您可以使用 kotlin 的协程来实现这一点。
您可以使用调用您的 api 请求的挂起函数启动协程,并保留在启动协程时返回的“作业”对象的引用以及当您的用户在前一个请求正在进行时发送另一个搜索请求时,您可以只需使用“job.isActive”检查之前的改造请求是否正在进行中,如果它处于活动状态,那么您可以调用“job.cancel()”来停止观察之前的 liveData 并开始一个新的 Job。
class MainViewModel @Inject constructor() : ViewModel()
// Job instance
private var job = Job()
fun requestApiForResponse(val searchQuery:String)
if(job?.isActive) // check if any previous job is running , if true then cancel that
job?.cancel()
job = GlobalScope.launch(Dispatchers.IO)
//call your retrofit Request here
override fun onCleared()
super.onCleared()
job.cancel()
查看这个github的仓库search functionality with liveData and coroutines
【讨论】:
以上是关于如何处理以前的请求并停止观察以前的 LiveData的主要内容,如果未能解决你的问题,请参考以下文章