使用RxBinding与RxJava实现按钮点击防重复请求的非ThrottleFirst方案
可选实现方案
下面三种方案均仅依赖RxJava和RxBinding实现,完全满足请求执行时忽略点击的需求:
方案1:使用exhaustMapSingle操作符(推荐)
exhaustMap系列操作符是专门应对这类场景的原生实现:只要当前内部请求流未完成,新的上游点击事件会被直接丢弃,不需要额外维护任何状态,代码侵入性最低。
修改后代码如下:
button.clicks() .exhaustMapSingle { Completable.fromCallable { usersViewModel.users(emptyList()) } .andThen(Request.users()) } .doOnNext { Toast .makeText(this, R.string.users_updated, Toast.LENGTH_LONG) .show() } .subscribe(usersViewModel::users) { Log.e(this::class.java.name, it.message, it) }
注:该操作符在RxJava 2.1及以上、RxJava 3全版本支持。
方案2:使用flatMapSingle的maxConcurrent参数
flatMap系列操作符均支持传入maxConcurrent参数限制同时订阅的内部流数量,将参数设为1时,后续的点击事件会被直接丢弃,效果和exhaustMapSingle完全一致。
修改后代码如下:
button.clicks() .flatMapSingle({ Completable.fromCallable { usersViewModel.users(emptyList()) } .andThen(Request.users()) }, 1) .doOnNext { Toast .makeText(this, R.string.users_updated, Toast.LENGTH_LONG) .show() } .subscribe(usersViewModel::users) { Log.e(this::class.java.name, it.message, it) }
方案3:配合状态位用filter过滤点击
如果你的项目使用的RxJava版本较低不支持exhaustMap,可以手动维护请求状态位来过滤重复点击,兼容性最好。
实现代码如下:
// 标记请求是否正在执行 var isRequesting = false button.clicks() // 仅请求未执行时响应点击 .filter { !isRequesting } .flatMapSingle { isRequesting = true Completable.fromCallable { usersViewModel.users(emptyList()) } .andThen(Request.users()) // 无论请求成功失败都重置状态位 .doOnEvent { _, _ -> isRequesting = false } } .doOnNext { Toast .makeText(this, R.string.users_updated, Toast.LENGTH_LONG) .show() } .subscribe(usersViewModel::users) { Log.e(this::class.java.name, it.message, it) }
注意:必须在请求的最终回调里重置状态位,避免请求报错后按钮永久无法点击。
内容的提问来源于stack exchange,提问作者Ahmadreza Zarei
相关产品推荐
相关产品推荐

