防止快速点击按钮并使用 rxjava 发出请求

ant*_*009 6 android kotlin rx-java2

我有以下方法可以请求从端点获取 pokemon。

我想通过快速单击将多次调用此方法的按钮来防止用户发出快速请求。我使用了油门 * 方法和去抖动。

基本上,如果用户在 300 毫秒的持续时间内快速点击按钮,我正在寻找它应该接受该持续时间内的最后一次点击。但是,我所经历的是所有请求都在提出。即如果用户在这段时间内快速点击 3 次,我仍然会收到 3 个请求。

   fun getPokemonDetailByName(name: String) {
        pokemonDetailInteractor.getPokemonDetailByName(name)
            .subscribeOn(pokemonSchedulers.background())
            .observeOn(pokemonSchedulers.ui())
            .toObservable()
            .throttleFirst(300, TimeUnit.MILLISECONDS)
            .singleOrError()
            .subscribeBy(
                onSuccess = { pokemon ->
                    pokemonDetailLiveData.value = pokemon
                },
                onError = {
                    Timber.e(TAG, it.localizedMessage)
                }
            ).addTo(compositeDisposable)
    }
Run Code Online (Sandbox Code Playgroud)

Bla*_*elt 7

基本上,如果用户在 300 毫秒的持续时间内快速点击按钮,我正在寻找它应该接受该持续时间内的最后一次点击

对我来说听起来更像是去抖操作员的行为。从文档

Debounce — 仅当一个特定的时间跨度过去了而没有发射另一个项目时,才从 Observable 发射一个项目

你可以在这里看到大理石图


cku*_*der 5

private val subject = PublishSubject.create<String>()

init {
    processClick()
}

fun onClick(name: String) {
    subject.onNext(name)
}

private fun processClick() {
    subject
        .debounce(300, TimeUnit.MILLISECONDS)
        .switchMap { getPokemonDetailByName(it) }
        .subscribe(
            { pokemonDetailLiveData.value = it },
            { Timber.e(TAG, it.localizedMessage) }
        )
}

private fun getPokemonDetailByName(name: String): Observable<Pokemon> =   
     pokemonDetailInteractor
        .getPokemonDetailByName(name)
        .subscribeOn(pokemonSchedulers.background())
        .observeOn(pokemonSchedulers.ui())
        .toObservable()
Run Code Online (Sandbox Code Playgroud)

在您的情况下,getPokemonDetailByName每次都会创建一个新的订阅。相反,将点击事件发送到 a Subject,创建对该流的单个订阅并应用debounce


ant*_*009 1

感谢所有的答案。

然而,我找到了一个使用 RxBinding 和去抖动运算符的解决方案。我在这里发帖是因为它可能对其他人有用。

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PokemonViewHolder {
    binding = PokemonListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
    val pokemonViewHolder = PokemonViewHolder(binding.root)

    pokemonViewHolder.itemView.clicks()
        .debounce(300, TimeUnit.MILLISECONDS)
        .subscribeBy(
            onNext = {
                val name = pokemonList[pokemonViewHolder.adapterPosition].name

                if(::pokemonTapped.isInitialized) {
                    pokemonTapped(name)
                }
            },
            onError = { Timber.e(it, "Failed to send pokemon request %s", it.localizedMessage) }
        ).addTo(compositeDisposable)

    return pokemonViewHolder
}
Run Code Online (Sandbox Code Playgroud)