Android端限制指定API每3秒调用一次,RxJava debounce不生效如何解决
问题原因
- 你当前的写法相当于创建了10个完全独立的Observable实例,每个实例只发射一次接口请求的结果,
debounce操作符是针对单个Observable的事件流做防抖,单个流只有一个事件的情况下debounce完全不会生效;且你在调用apiRepo.test()的时候请求就已经触发了,后续的操作符根本拦不住请求发送。 debounce本身的作用是:当上游连续发送事件时,只有当事件发送后等待指定时间没有新的事件发送,才会把最后一个事件发往下游,既不能拦截请求发送,也不符合你要保留第一个事件的需求。
正确实现方案
你需要把所有的请求触发动作整合成同一个事件流,用限流操作符处理后再实际发起请求,有两种常见实现方式:
方案1:RxJava原生实现(使用throttleFirst操作符)
throttleFirst的作用是指定时间窗口内,只放行第一个事件,正好匹配你3秒内只保留第一次调用的需求,示例代码如下:
// 先创建一个PublishSubject作为请求触发器,所有要调用test接口的地方都给它发事件 val requestTrigger = PublishSubject.create<Unit>() // 对触发器的事件流做限流,3秒窗口内只取第一个事件,再实际发起请求 requestTrigger .throttleFirst(3, TimeUnit.SECONDS) .flatMapSingle { apiRepo.test() } .subscribe( { /* 处理接口返回结果 */ }, { Timber.e(it) } ) // 模拟10次连续调用请求 repeat(10) { requestTrigger.onNext(Unit) }
方案2:协程实现(适配你常用的技术栈)
如果平时用协程更多,可以直接用共享流配合限流逻辑实现:
// 定义一个MutableSharedFlow作为触发器 val requestFlow = MutableSharedFlow<Unit>() viewModelScope.launch { requestFlow // 3秒采样窗口内只取第一个事件 .sample(3000, start = 0) .collect { val result = apiRepo.test() // 挂起函数调用接口 // 处理返回结果 } } // 模拟10次连续调用 repeat(10) { viewModelScope.launch { requestFlow.emit(Unit) } }
优化建议
如果你需要做全局的/test接口限流,不管哪里调用都要遵循3秒一次的规则,可以直接把限流逻辑封装到apiRepo.test()方法内部,外部调用时不需要额外处理,避免漏加限流逻辑。
内容的提问来源于stack exchange,提问作者MaaAn13
相关产品推荐
相关产品推荐

