在我的Android Kotlin项目中,我在协同关系中调用一个webservice(MyWebservice
只是一个管理webservice调用的自定义类):
fun searchForItems(userInput: String)
{
CoroutineScope(Dispatchers.IO + Job()).launch {
val listOfItems = myWebService.call(userInput)
}
}
每当用户在edittext
中键入一个字符时,该方法就会被调用,因此应用程序调用一个Web服务,该服务返回一个与他的请求匹配的项目列表。 但我想优化一下。
假设用户键入单词:“Apple”。 为了最小化webservice调用的数量,下面是我想要实现的目标:
实现这一目标的最佳做法是什么? 或者有没有更好的方法来最大限度地减少webservice调用的数量?
谢了。
使用Kotlin coroutines,我是这样解决的:
class SomeViewModel : ViewModel() {
private var searchJob: Job? = null
fun search(userInput: String) {
searchJob?.cancel() // cancel previous job when user enters new letter
searchJob = viewModelScope.launch {
delay(300) // add some delay before search, this function checks if coroutine is canceled, if it is canceled it won't continue execution
val listOfItems = myWebService.call(userInput)
...
}
}
}
当用户输入第一个字母时,调用search()
函数,启动协同查询,并将该协同查询的job
保存到searchjob
中。 然后调用delay(300)
函数,在调用WebService之前等待另一个用户输入。 如果用户在300毫秒过期之前输入另一个字母,将再次调用Search()
函数,并使用SearchJob?。Cancel()
函数取消上一个协同查询,并且在第一个协同查询中不会调用WebService。
你需要去抖。 无论是否相互关联,您都不应该用每个活跃用户的每个字母来调用web服务。 如果你的应用程序同时被很多人使用,最终会导致网络服务被DDOS。
因为您使用的是Kotlin,所以您可以使用Flow而不是coroutines。 它带有一个内置的去抖
方法。 此外,信流很容易被建模为流。 它应该是这样的(我不确定它是否运行,但你明白了):
textFlow = flow {
myTextView.doOnTextChanged { text, start, count, after -> emit(text)}
}.debounce(1000)
更复杂的替代方案是RXJava的debounce
运算符。
您还可以尝试使用Lupajz的去抖扩展的LiveData
或者您也可以滚动您自己的解决方案。