提问者:小点点

如何使用Kotlin Coroutines最小化Web服务调用的数量?


在我的Android Kotlin项目中,我在协同关系中调用一个webservice(MyWebservice只是一个管理webservice调用的自定义类):

fun searchForItems(userInput: String)
{
    CoroutineScope(Dispatchers.IO + Job()).launch {
        val listOfItems = myWebService.call(userInput)
    }
}

每当用户在edittext中键入一个字符时,该方法就会被调用,因此应用程序调用一个Web服务,该服务返回一个与他的请求匹配的项目列表。 但我想优化一下。

假设用户键入单词:“Apple”。 为了最小化webservice调用的数量,下面是我想要实现的目标:

  • 当用户键入第一个字母(a)时,Web服务称为
  • 当用户键入下一个字母时,只要第一个调用尚未返回,就不会有新的webservice调用(假设他有足够的时间键入下一个字母(pple))
  • 当完成第一个webservice调用时,将使用新的用户输入(apple)自动完成新的调用

实现这一目标的最佳做法是什么? 或者有没有更好的方法来最大限度地减少webservice调用的数量?

谢了。


共2个答案

匿名用户

使用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

或者您也可以滚动您自己的解决方案。