Android面试题库
Kotlin特性
Flow

Kotlin Flow

基础概念

1. 什么是Flow?

  1. 定义

    • 冷流数据流
    • 基于协程的响应式编程组件
    • 异步数据流序列
  2. 特点

    • 冷流特性:只有订阅时才会发射数据
    • 背压处理:自动处理生产和消费速度不匹配
    • 协程支持:完整的协程集成
    • 取消支持:可以自动取消

面试题解析

1. Flow的基本组件

  1. Flow构建器
val flow = flow {
    for (i in 1..3) {
        delay(100)
        emit(i)
    }
}
  1. StateFlow
private val _state = MutableStateFlow(0)
val state: StateFlow<Int> = _state.asStateFlow()
  1. SharedFlow
private val _events = MutableSharedFlow<Event>()
val events = _events.asSharedFlow()

2. Flow的操作符

  1. 转换操作符
flow.map { value -> value * 2 }
    .filter { value -> value > 0 }
    .take(5)
  1. 组合操作符
val flow1 = flowOf(1, 2, 3)
val flow2 = flowOf("a", "b", "c")
 
flow1.zip(flow2) { number, string ->
    "$number$string"
}.collect { println(it) }

3. Flow的上下文

  1. flowOn
flow {
    emit(performComputation())
}.flowOn(Dispatchers.Default)
 .collect { value ->
     updateUI(value)
 }
  1. 异常处理
flow {
    emit(1)
    throw RuntimeException("Error")
}.catch { e ->
    emit(-1)
}.collect { value ->
    println(value)
}

4. StateFlow vs SharedFlow

  1. StateFlow特点
class ViewModel {
    private val _uiState = MutableStateFlow(UiState())
    val uiState = _uiState.asStateFlow()
    
    fun updateState() {
        _uiState.update { it.copy(loading = true) }
    }
}
  1. SharedFlow特点
class EventBus {
    private val _events = MutableSharedFlow<Event>(replay = 0)
    val events = _events.asSharedFlow()
    
    suspend fun emit(event: Event) {
        _events.emit(event)
    }
}

实战技巧

1. 网络请求处理

fun getUsers(): Flow<List<User>> = flow {
    while (true) {
        val users = api.getUsers()
        emit(users)
        delay(5000) // 5秒刷新一次
    }
}.catch { e ->
    emit(emptyList())
}.flowOn(Dispatchers.IO)

2. UI状态管理

data class UiState(
    val isLoading: Boolean = false,
    val data: List<Item> = emptyList(),
    val error: String? = null
)
 
class MainViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(UiState())
    val uiState = _uiState.asStateFlow()
    
    fun loadData() {
        viewModelScope.launch {
            _uiState.update { it.copy(isLoading = true) }
            try {
                val data = repository.getData()
                _uiState.update { it.copy(
                    isLoading = false,
                    data = data
                )}
            } catch (e: Exception) {
                _uiState.update { it.copy(
                    isLoading = false,
                    error = e.message
                )}
            }
        }
    }
}

3. 事件处理

class EventViewModel : ViewModel() {
    private val _events = MutableSharedFlow<UiEvent>()
    val events = _events.asSharedFlow()
    
    fun handleAction(action: UserAction) {
        viewModelScope.launch {
            when (action) {
                is UserAction.Click -> _events.emit(UiEvent.ShowToast("Clicked"))
                is UserAction.Swipe -> _events.emit(UiEvent.Navigate("next"))
            }
        }
    }
}

注意事项

  1. 性能优化

    • 适当使用缓存
    • 避免不必要的转换
    • 合理使用背压策略
  2. 内存管理

    • 及时取消收集
    • 避免内存泄漏
    • 使用生命周期感知型收集器

选择题

  1. Flow的哪个操作符会切换执行上下文? A. map B. flowOn C. filter D. take

答案:B 解析:flowOn操作符用于更改Flow的上游操作的执行上下文。

  1. 以下哪个Flow类型具有粘性事件特性? A. Flow B. SharedFlow C. StateFlow D. ChannelFlow

答案:C 解析:StateFlow总是保持最新值,新订阅者会立即收到当前值。

问答题

  1. 解释Flow中的背压是什么,以及如何处理背压问题。

答案:

  • 背压概念:

    1. 生产者和消费者速度不匹配
    2. 数据积压导致内存问题
    3. 需要控制数据流速率
  • 处理方式:

    1. buffer:缓冲数据
    2. conflate:只保留最新值
    3. collectLatest:取消旧值处理
    4. sample:采样数据
  1. 比较Flow和Channel的区别。

答案:

  • Flow特点:

    1. 冷流,惰性求值
    2. 支持丰富的操作符
    3. 适合数据流转换
  • Channel特点:

    1. 热流,立即执行
    2. 用于协程间通信
    3. 类似于队列的概念

编程题

  1. 实现一个带缓存的网络请求Flow。
class CachedRepository(
    private val api: Api,
    private val db: Database
) {
    fun getData(): Flow<Result<Data>> = flow {
        // 先发射缓存数据
        val cached = db.getData()
        emit(Result.success(cached))
        
        try {
            // 请求新数据
            val fresh = api.fetchData()
            // 更新缓存
            db.saveData(fresh)
            emit(Result.success(fresh))
        } catch (e: Exception) {
            emit(Result.failure(e))
        }
    }.catch { e ->
        emit(Result.failure(e))
    }.flowOn(Dispatchers.IO)
}
 
// 使用示例
class ViewModel {
    fun loadData() {
        viewModelScope.launch {
            repository.getData()
                .onEach { result ->
                    when (result) {
                        is Result.Success -> updateUI(result.data)
                        is Result.Failure -> showError(result.error)
                    }
                }
                .catch { e -> handleError(e) }
                .collect()
        }
    }
}

总结

  1. 核心概念

    • Flow基础API
    • 操作符使用
    • 上下文管理
    • 异常处理
  2. 最佳实践

    • 合理使用Flow类型
    • 正确处理生命周期
    • 优化性能
    • 处理背压
  3. 应用场景

    • 网络请求
    • UI状态管理
    • 事件处理
    • 数据转换