You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中如何根据特定条件从MutableList移除元素

基于Kotlin Flow实现带超时自动移除的扫描列表管理

核心需求梳理

  • 向MutableList中添加唯一的扫描结果元素(避免重复)
  • 实现两种元素移除逻辑:
    • 当扫描Flow停止发射数据时,处理列表清理
    • 某个元素最后一次被扫描到后,超过30秒未再次出现则自动移除

优化后的完整实现代码

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onCompletion
import java.util.concurrent.ConcurrentHashMap

class ItemList {
    // 适配Compose:如果需要自动触发重组,替换为mutableStateListOf<ScanResults>()
    val scanResultList = mutableListOf<ScanResults>()
    // 记录每个设备最后一次被扫描到的时间戳,线程安全的Map
    private val lastSeenTimestamps = ConcurrentHashMap<Device, Long>()
    // 定期清理超时元素的后台协程任务
    private var cleanupJob: Job? = null

    fun simulateScanFlow(): Flow<ScanResults> = flow {
        (0..20).forEach {
            delay(200L)
            val result = when (it) {
                in 10..12 -> ScanResults(Device("item in 10-12 range"))
                in 15..18 -> ScanResults(Device("item in 15-18 range"))
                else -> ScanResults(Device("item out of range"))
            }
            emit(result)
        }
    }

    fun startScanning() = runBlocking {
        // 启动每秒一次的超时检查任务
        cleanupJob = launch {
            while (isActive) {
                delay(1000L)
                removeTimeoutItems()
            }
        }

        simulateScanFlow()
            .catch { e -> println("扫描异常: ${e.message}") }
            .onCompletion {
                // Flow停止发射时,停止清理任务并清空列表
                cleanupJob?.cancel()
                scanResultList.clear()
                lastSeenTimestamps.clear()
                println("扫描已停止,列表已清空")
            }
            .collect { result ->
                processScanResult(result)
            }
    }

    private fun processScanResult(result: ScanResults) {
        result.device?.let { device ->
            // 更新当前设备的最后活跃时间
            lastSeenTimestamps[device] = System.currentTimeMillis()
            // 仅当列表中无重复元素时添加
            if (!scanResultList.contains(result)) {
                scanResultList.add(result)
                println("已添加元素: ${device.name}")
            }
        }
    }

    private fun removeTimeoutItems() {
        val currentTime = System.currentTimeMillis()
        // 筛选出超过30秒未出现的设备
        val timeoutDevices = lastSeenTimestamps.filter { (_, timestamp) ->
            currentTime - timestamp > 30000L
        }.keys

        timeoutDevices.forEach { device ->
            scanResultList.removeIf { it.device == device }
            lastSeenTimestamps.remove(device)
            println("已移除超时元素: ${device.name}")
        }
    }

    data class ScanResults(val device: Device? = null)
    data class Device(val name: String? = null)
}

fun main() {
    ItemList().startScanning()
}

关键实现说明

  1. 超时元素自动移除

    • 用lastSeenTimestamps记录每个设备的最后扫描时间,通过后台协程每秒检查一次
    • 一旦设备超过30秒未被扫描到,就从列表和时间戳映射中移除,确保列表只保留活跃的扫描结果
  2. Flow停止时的清理逻辑

    • 通过onCompletion操作符监听Flow的结束事件(包括正常完成、异常终止)
    • 此时取消后台清理任务,清空扫描列表和时间戳映射,完成收尾工作
  3. 重复元素判断优化

    • 由于ScanResults和Device都是data class,默认实现了equals和hashCode,直接用contains就能判断元素是否重复,省去了额外的重复检查方法
  4. Compose适配注意

    • 如果需要在Compose中使用,将mutableListOf替换为mutableStateListOf,这样列表的变化会自动触发Compose重组,完全满足你无法使用Set的场景需求

内容的提问来源于stack exchange,提问作者Compose Learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:31:12