[Fix] Scanner item flicker

This commit is contained in:
2026-06-27 14:14:44 +07:00
parent 7ef4b7d1cf
commit 9ed28e11d9
@@ -37,6 +37,7 @@ import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import kotlin.time.TimeSource import kotlin.time.TimeSource
import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.ExperimentalUuidApi
@@ -45,6 +46,10 @@ data class ConnectedDevice(
val advertisement: Advertisement, val advertisement: Advertisement,
val state: State val state: State
) )
data class AdvertisementMark(
val advertisement: Advertisement,
val timeMark: TimeSource.Monotonic.ValueTimeMark
)
@OptIn(ExperimentalUuidApi::class) @OptIn(ExperimentalUuidApi::class)
class ScannerViewModel( class ScannerViewModel(
private val bleManager: BleManager, private val bleManager: BleManager,
@@ -54,7 +59,7 @@ class ScannerViewModel(
private val scannerRepository: ScannerRepository private val scannerRepository: ScannerRepository
) : ViewModel() { ) : ViewModel() {
companion object { companion object {
private val SCAN_TIMEOUT = 1.seconds private val SCAN_TIMEOUT = 5.seconds
private val CONNECTION_TIMEOUT = 5.seconds private val CONNECTION_TIMEOUT = 5.seconds
private const val MAX_LOG_ENTRIES = 50 private const val MAX_LOG_ENTRIES = 50
} }
@@ -79,7 +84,7 @@ class ScannerViewModel(
private var cleanupJob: Job? = null private var cleanupJob: Job? = null
private val connectionJobs = mutableMapOf<String, Job>() private val connectionJobs = mutableMapOf<String, Job>()
private val advertisementMap = mutableMapOf<String, Pair<Advertisement, TimeSource.Monotonic.ValueTimeMark>>() private val advertisementMap = mutableMapOf<String, AdvertisementMark>()
/** Bonded device */ /** Bonded device */
private val bondedIds = mutableSetOf<String>() // Cache private val bondedIds = mutableSetOf<String>() // Cache
@@ -118,7 +123,12 @@ class ScannerViewModel(
connect(advertisement) connect(advertisement)
} else { } else {
val now = TimeSource.Monotonic.markNow() val now = TimeSource.Monotonic.markNow()
advertisementMap[advertisement.identifier.toString()] = advertisement to now val entry = advertisementMap[bleId]
if (entry != null) {
advertisementMap[bleId] = entry.copy(advertisement = advertisement, timeMark = now)
} else {
advertisementMap[bleId] = AdvertisementMark(advertisement, now)
}
startCleanupJob() startCleanupJob()
updateDeviceList() updateDeviceList()
} }
@@ -131,8 +141,8 @@ class ScannerViewModel(
if (cleanupJob?.isActive == true) return if (cleanupJob?.isActive == true) return
cleanupJob = viewModelScope.launch { cleanupJob = viewModelScope.launch {
while (advertisementMap.isNotEmpty() && isActive) { while (advertisementMap.isNotEmpty() && isActive) {
delay(1000) delay(5000)
val keysToRemove = advertisementMap.filter { it.value.second.elapsedNow() > SCAN_TIMEOUT }.keys val keysToRemove = advertisementMap.filter { it.value.timeMark.elapsedNow() > SCAN_TIMEOUT }.keys
if (keysToRemove.isNotEmpty()) { if (keysToRemove.isNotEmpty()) {
keysToRemove.forEach { advertisementMap.remove(it) } keysToRemove.forEach { advertisementMap.remove(it) }
updateDeviceList() updateDeviceList()
@@ -147,8 +157,10 @@ class ScannerViewModel(
} }
private fun updateDeviceList() { private fun updateDeviceList() {
_devices.value = advertisementMap.values.map { it.first } val newList = advertisementMap.values.map { it.advertisement }
// .sortedByDescending { it.rssi } // Fix flicker if (newList != _devices.value) {
_devices.value = newList
}
} }
fun stopScan() { fun stopScan() {