一、先说说 Flow 是什么?
在 Android 开发中,Flow 是 Kotlin 提供的一种异步数据流 ,用来安全地处理随时间变化的数据,比如:
- 从数据库实时读取用户列表
- 网络请求返回的分页数据
- 用户输入的搜索关键词(防抖后)
- 传感器数据(如位置、加速度)
Flow 的特点是:冷流(cold stream) ------ 只有被 collect(收集)时才会开始执行,避免资源浪费。
二、那 map 是干什么的?
map的作用:把 Flow 中的每一个值"转换"成另一个值。
你可以把它想象成一个"加工厂":
- 原料进来(原始数据)
- 经过加工(你定义的转换逻辑)
- 成品出去(新数据)
它不会改变 Flow 的结构 ,只是变换每个元素的内容。
三、举个简单例子 🌰
假设你有一个 Flow,发出用户的 ID:
val userIds: Flow<Int> = flowOf(1, 2, 3)
你想把每个 ID 转换成对应的用户名(比如 "User_1"),就可以用 map:
val userNames: Flow<String> = userIds.map { id ->
"User_$id"
}
现在 userNames 是一个发出 "User_1", "User_2", "User_3" 的 Flow。
四、Android 实际开发场景 📱
场景:从 Room 数据库获取 User 实体,但 UI 只需要显示名字
假设你的数据库实体是:
data class UserEntity(
val id: Int,
val name: String,
val email: String
)
DAO 返回一个 Flow:
@Query("SELECT * FROM users")
fun getAllUsers(): Flow<List<UserEntity>>
但在 ViewModel 或 UI 层,你只想显示用户名列表(List<String>),不想暴露整个实体。
✅ 这时候就用 map 转换:
val userNames: Flow<List<String>> = userRepository.getAllUsers()
.map { userEntities ->
userEntities.map { it.name } // 把 List<UserEntity> 转成 List<String>
}
🔍 注意:这里用了两次
map!
- 外层
map是 Flow 的 map(转换 Flow 中的每个值)- 内层
map是 List 的 map(转换列表中的每个元素)
最终,你的 UI 可以这样 collect:
lifecycleScope.launch {
userNames.collect { names ->
adapter.updateNames(names) // 更新 RecyclerView
}
}
五、map 的关键特点
| 特点 | 说明 |
|---|---|
| ✅ 同步转换 | map 中的 lambda 是阻塞式执行的(不能直接调用 suspend 函数) |
| ⚠️ 不能挂起 | 如果你需要在转换中做网络请求或数据库操作(suspend),要用 transform 或 mapLatest + async 等 |
| 🔁 一对一映射 | 输入一个值 → 输出一个值(不能过滤、不能发多个) |
❗ 如果你在
map里想调用 suspend 函数,会报错!正确做法是改用
transform:
flow.transform { value ->
val result = someSuspendFunction(value) // ✅ 可以挂起
emit(result) // 手动发射
}
六、常见误区
❌ 误区1:在 map 里做耗时操作
// 错误!map 不是协程作用域,不能直接调用 suspend 函数
someFlow.map {
fetchDataFromNetwork(it) // 编译错误!
}
✅ 正确做法:用 transform 或提前在 Repository 层处理好。
❌ 误区2:以为 map 会启动 Flow
val mapped = originalFlow.map { ... }
// 此时什么都没发生!Flow 是冷的,必须 collect 才会执行
七、和其他操作符对比
| 操作符 | 用途 |
|---|---|
map |
一对一转换(同步) |
transform |
自定义转换(可挂起,可 emit 多次) |
filter |
过滤元素 |
mapLatest |
类似 map,但会取消上一个未完成的转换(适合搜索框) |
八、总结一句话
map是 Flow 中最常用的转换操作符,用于将流中的每个元素同步地"变成"另一种形式,特别适合在 Android 中做数据模型到 UI 模型的转换。
它让你的代码更清晰、更函数式,而且和 LiveData / StateFlow 配合起来非常流畅!