Reputation: 16609
I use this in Kotlin to debounce based on condition:
// variables
private val subject_isUpdating = PublishSubject.create<Int>()
var lastClickedItem = -1
// inside onCreate
adapter_cartProducts.setOnItemClickedListener { position ->
subject_isUpdating.onNext(position)
}
// subscribing
subject_isUpdating
.debounce
{ position ->
// here if lastClickedItem changed, no debounce
if(position != lastClickedItem) {
lastClickedItem = position
Observable.empty()
}
// else if same item clicked -> debounce
else Observable.timer(300, TimeUnit.MILLISECONDS) }
.subscribe({ position ->
updateOnWS(position, adapter_cartProducts.items[position])
}, { error ->
Timber.e(error) // printing the error
})
This is the debounce selector function used from the RxJava:
/**
* Returns an Observable that mirrors the source ObservableSource, except that it drops items emitted by the
* source ObservableSource that are followed by another item within a computed debounce duration.
* <p>
* <img width="640" height="425" src="https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/debounce.f.png" alt="">
* <dl>
* <dt><b>Scheduler:</b></dt>
* <dd>This version of {@code debounce} does not operate by default on a particular {@link Scheduler}.</dd>
* </dl>
*
* @param <U>
* the debounce value type (ignored)
* @param debounceSelector
* function to retrieve a sequence that indicates the throttle duration for each item
* @return an Observable that omits items emitted by the source ObservableSource that are followed by another item
* within a computed debounce duration
* @see <a href="http://reactivex.io/documentation/operators/debounce.html">ReactiveX operators documentation: Debounce</a>
*/
public final <U> Observable<T> debounce(Function<? super T, ? extends ObservableSource<U>> debounceSelector) {
ObjectHelper.requireNonNull(debounceSelector, "debounceSelector is null");
return RxJavaPlugins.onAssembly(new ObservableDebounce<T, U>(this, debounceSelector));
}
The idea of this code, user will click on item of list, and the item will be updated on webservice when user stops clicking for 400ms or clicks another item
Is that possible to be done in RxSwift ?
Upvotes: 0
Views: 1442
Reputation: 1
I feel the flatMapLatest can be used to solve the conditional debounce needed here.
subject
.flatMapLatest { position in
if position != lastClickedPosition {
lastClickedItem = position
return Observable.just(position)
} else {
return Observable.just(position).delay(.milliseconds(300), scheduler: scheduler)
}
}
// Subscribe
I have this article on creating variable debounce using combine and RxSwift. Please check this out. https://medium.com/dev-genius/part-1-variable-time-debounce-in-swift-30a987511c6c
Upvotes: 0
Reputation: 33967
I can't say I especially like the code you presented because of its dependency on the external variable.
Here's an operator that does what you want:
extension ObservableType where E: Equatable {
func throttleUnlessChanged(_ dueTime: TimeInterval, scheduler: SchedulerType) -> Observable<E> {
return Observable.create { observer in
let lock = NSRecursiveLock()
var last: E?
var lastTime: RxTime?
return self.subscribe { event in
lock.lock(); defer { lock.unlock() }
switch event {
case .next(let element):
let now = scheduler.now
let timeIntervalSinceLast = lastTime != nil ? now.timeIntervalSince(lastTime!) : dueTime
if element != last {
observer.onNext(element)
last = element
lastTime = now
}
else if timeIntervalSinceLast >= dueTime {
observer.onNext(element)
last = element
lastTime = now
}
case .error(let error):
observer.onError(error)
case .completed:
observer.onCompleted()
}
}
}
}
}
Here's a gist complete with tests: https://gist.github.com/dtartaglia/f5b041facfdcdd64630e0cb8cfc2cc5b
Upvotes: 2