Flow 和 LiveData 之操作符:throttleFirst、 throttleLast 、throttleLatest、debounce
文章目录
前言
因为使用kotlin
和协程后准备移除RxJava
,其中大部分功能,可以使用Flow
进行替代,但是出现了部分操作符功能缺少,所有进行改进。
这是一遍没有检验的文章,部分操作操作符只是按逻辑写的,没有测试。有几个只是按自己的需求写的,可能和RxJava的存在差异
一、Flow 之操作符扩展
1. ThrottleFirst
fun <T> Flow<T>.throttleFirst(duration: Long = 1000L) = this.throttleFirstImpl(duration)
fun <T> Flow<T>.throttleFirstImpl(periodMillis: Long): Flow<T> {
return flow {
var lastTime = 0L
collect { value ->
val currentTime = System.currentTimeMillis()
if (currentTime - lastTime >= periodMillis) {
lastTime = currentTime
emit(value)
}
}
}
}
2. ThrottleLast
fun <T> Flow<T>.throttleLast(duration: Long = 1000L) = this.sample(duration)
3. ThrottleLatest
fun <T> Flow<T>.throttleLatest(duration: Long = 1000L) = this.throttleLatestImpl(duration)
internal fun <T> Flow<T>.throttleLatestImpl(periodMillis: Long): Flow<T> {
return channelFlow {
var lastValue: T?
var timer: Timer? = null
onCompletion { timer?.cancel() }
collect { value ->
lastValue = value
if (timer == null) {
timer = Timer()
timer?.scheduleAtFixedRate(
object : TimerTask() {
override fun run() {
val value = lastValue
lastValue = null
if (value != null) {
launch {
send(value as T)
}
} else {
timer?.cancel()
timer = null
}
}
},
0,
periodMillis
)
}
}
}
}
4. Debounce (Flow自带)
flow {
emit(1)
delay(90.milliseconds)
emit(2)
delay(90.milliseconds)
emit(3)
delay(1010.milliseconds)
emit(4)
delay(1010.milliseconds)
emit(5)
}.debounce(1000.milliseconds)
一、LiveData 之操作符扩展
1. ThrottleFirst
/*** @Author stj
* * @Date 2021/10/8-18:38
* * @Email 375105540@qq.com
* * 间隔固定时间内,取第一个的值
*/
fun <T> LiveData<T>.throttleFirst(duration: Long = 1000L) = MediatorLiveData<T>().also { mld ->
val source = this
val handler = Handler(Looper.getMainLooper())
val isUpdate = AtomicBoolean(true)
val runnable = Runnable {
isUpdate.set(true)
}
mld.addSource(source) {
if (isUpdate.compareAndSet(true,false)){
mld.value = source.value
handler.postDelayed(runnable, duration)
}
}
}
2. ThrottleLast
fun <T> LiveData<T>.throttleLast(duration: Long = 1000L) = MediatorLiveData<T>().also { mld ->
val source = this
val handler = Handler(Looper.getMainLooper())
val isUpdate = AtomicBoolean(true)
val runnable = Runnable {
if (isUpdate.compareAndSet(false,true)){
mld.value = source.value
}
}
mld.addSource(source) {
if (isUpdate.compareAndSet(true,false)) {
handler.postDelayed(runnable, duration)
}
}
}
3. ThrottleLatest
fun <T> LiveData<T>.throttleLatest(duration: Long = 1000L) = MediatorLiveData<T>().also { mld ->
val source = this
val isFirst = AtomicBoolean(true)
val handler = HandlerCompat.createAsync(Looper.getMainLooper())
val isUpdate = AtomicBoolean(true)
val runnable = Runnable {
if (isUpdate.compareAndSet(false,true)){
mld.value = source.value
}
}
mld.addSource(source) {
if (isFirst.compareAndSet(true,false)){
mld.value = source.value
}
if (isUpdate.compareAndSet(true,false)) {
handler.postDelayed(runnable, duration)
}
}
}
4. Debounce
fun <T> LiveData<T>.debounce(duration: Long = 1000L) = MediatorLiveData<T>().also { mld ->
val source = this
val handler = HandlerCompat.createAsync(Looper.getMainLooper())
val runnable = Runnable {
mld.value = source.value
}
mld.addSource(source) {
handler.removeCallbacks(runnable)
handler.postDelayed(runnable, duration)
}
}
Tip
有几个没有测试过,因为需求需要了,所有改了几个,其他结果是按逻辑写的,可能会有问题