用通俗易懂 + Android 开发实战的方式讲解 Kotlin Flow 中的 filter 操作符

一、一句话理解 filter

filter 的作用是:只让"符合条件"的数据通过,不符合的直接丢掉。

你可以把它想象成一个"筛子":

  • 数据流进来
  • filter 按你定的规则检查每个值
  • 只有满足条件的才能流出去,其他的被过滤掉

二、基本语法

复制代码
flow.filter { value ->
    // 返回 true:保留这个值
    // 返回 false:丢弃这个值
}

三、简单例子 🌰

假设你有一个发出数字的 Flow:

复制代码
val numbers = flowOf(1, 2, 3, 4, 5, 6)

你只想处理偶数

复制代码
val evenNumbers = numbers.filter { it % 2 == 0 }
// 结果 Flow 会发出:2, 4, 6

四、Android 实战场景 📱

场景1:只显示"已激活"的用户

假设你从数据库获取用户列表:

复制代码
data class User(val id: Int, val name: String, val isActive: Boolean)

// Repository 返回 Flow<List<User>>
val allUsers: Flow<List<User>> = userRepository.getAllUsers()

但 UI 只想显示 isActive == true 的用户。

✅ 用 filter(注意:这里是对列表中的每个用户过滤):

复制代码
val activeUsers: Flow<List<User>> = allUsers.map { users ->
    users.filter { user -> user.isActive } // 这是 List 的 filter
}

🔍 注意:这里用的是 List 的 filter ,因为 Flow 发出的是整个列表。

如果 Flow 是逐个发出 User(比如 Flow<User>),那就直接用 Flow 的 filter

复制代码
val activeUserStream: Flow<User> = userEventStream.filter { it.isActive }

场景2:搜索框防抖后过滤空输入

用户在搜索框输入,你用 callbackFlowStateFlow 监听输入:

复制代码
val searchQueries: StateFlow<String> = mutableSearchQuery.asStateFlow()

你不希望在用户输入空字符串或长度太短时发起网络请求:

复制代码
lifecycleScope.launch {
    searchQueries
        .map { it.trim() }          // 先 trim
        .filter { it.length >= 2 }  // 只有 >=2 个字符才继续
        .debounce(300)              // 防抖
        .collect { query ->
            searchRepository.search(query) // 安全发起请求
        }
}

✅ 这样就避免了无效请求(比如搜一个字母或空格)。


五、filter 的关键特点

特点 说明
同步判断 lambda 里不能直接调用 suspend 函数(和 map 一样)
🔽 可能"卡住" 如果所有数据都不符合条件,下游就收不到任何值(这是正常行为!)
🔄 不改变数据类型 输入是 Flow<T>,输出还是 Flow<T>,只是元素变少了

六、常见误区

❌ 误区1:在 filter 里做网络请求或数据库查询
复制代码
someFlow.filter { value ->
    someSuspendFunction(value) // ❌ 编译错误!不能挂起
}

✅ 正确做法:如果需要异步判断,考虑用 transform 或提前在 Repository 层处理。

❌ 误区2:以为 filter 会"跳过" collect
复制代码
flow.filter { it > 5 }.collect { println(it) }
// 如果所有值 ≤5,collect 里的代码根本不会执行 ------ 这是正确的!

这其实是 filter 的正常行为:没有符合条件的数据,就不发射


七、和其他操作符搭配使用(超常用!)

Flow 的强大在于链式调用,比如:

复制代码
flowOf("apple", "banana", "cherry", "date")
    .filter { it.length > 5 }     // 只保留长度 >5 的
    .map { it.uppercase() }       // 转大写
    .collect { println(it) }      // 输出:BANANA, CHERRY

在 Android 中,你经常会看到这样的链:

复制代码
searchQuery
    .map { it.trim() }
    .filter { it.isNotEmpty() }
    .debounce(400)
    .distinctUntilChanged()
    .map { performSearch(it) }
    .catch { showError(it) }
    .collect { updateUI(it) }

八、总结一句话

filter 是 Flow 中用来"筛选数据"的操作符,只让满足条件的元素继续流动,非常适合在 Android 开发中做输入验证、状态过滤、避免无效操作等场景。

它和 map 一样,是 Flow 最基础、最常用的"组合积木"之一。

相关推荐
峥嵘life7 小时前
Android16 311Y3 EAP-TLS 网络连接失败分析与修复总结
android·开发语言·人工智能·php
Kapaseker8 小时前
破坏性更新 - 解读 Jetpack Compose 1.12
android·kotlin
雨白9 小时前
我的 UML 学习笔记:结合 Android 实例看懂 4 种常用图表
android·架构
怣疯knight9 小时前
快速判断apk有没有支持16kb页面标准
android
风流 少年10 小时前
Spring AI 2.0:Advisor
android·人工智能·spring
mqiqe10 小时前
AgentScope Java Harness:4. 双层记忆系统 让 Agent 拥有真正的“长期大脑“
java·开发语言
gugucoding10 小时前
46. 【Java】JUC并发工具:让并发更简单
java·开发语言
Nebula_g11 小时前
JavaSE基础语法:面向对象高级(代码中的成分)
java·开发语言·编程·javase·技术栈·高级语法
for_ever_love__11 小时前
python基础语法学习: 异常的传递性
开发语言·python·学习
依然鸣11 小时前
PTA团体程序设计天梯赛L1真题讲解L1-077-080
开发语言·c++·算法·深度优先·pat考试·图论