Android callbackFlow 使用场景详解
什么是 callbackFlow?
callbackFlow 是 Kotlin Flow 的一个构建器,专门用于将基于回调的异步 API 转换为 Flow 。
它解决了传统回调地狱问题,使代码更加简洁和可读。
核心使用场景
1. 📍 位置监听(Location Updates)
将 LocationManager 或 FusedLocationProviderClient 的回调转换为 Flow:
kotlin
/**
* 将位置更新回调转换为 Flow
* 使用 callbackFlow 持续监听位置变化
*/
fun LocationManager.locationFlow(provider: String): Flow<Location> = callbackFlow {
// 创建位置监听器
val mLocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
// 发送位置数据到 Flow
trySend(location)
}
override fun onProviderDisabled(provider: String) {
// 关闭 Flow 并携带异常信息
cancel(CancellationException("Provider disabled: $provider"))
}
}
// 注册位置监听
requestLocationUpdates(provider, 1000L, 0f, mLocationListener)
// 当 Flow 被取消时,注销监听器,防止内存泄漏
awaitClose {
removeUpdates(mLocationListener)
}
}
kotlin
/**
* 位置监听测试代码
*/
fun testLocationFlow() {
val scope = CoroutineScope(Dispatchers.Main)
scope.launch {
locationManager.locationFlow(LocationManager.GPS_PROVIDER)
.collect { location ->
println("纬度: ${location.latitude}, 经度: ${location.longitude}")
}
}
}
2. 🌐 网络状态监听(Network State)
监听网络连接状态变化:
kotlin
/**
* 监听网络连接状态变化
* 将 ConnectivityManager 的回调转换为 Flow
*/
fun Context.networkStateFlow(): Flow<Boolean> = callbackFlow {
val mConnectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
// 创建网络回调
val mNetworkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
// 网络可用,发送 true
trySend(true)
}
override fun onLost(network: Network) {
// 网络断开,发送 false
trySend(false)
}
}
val mRequest = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
// 注册网络回调
mConnectivityManager.registerNetworkCallback(mRequest, mNetworkCallback)
// Flow 取消时注销回调
awaitClose {
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback)
}
}
kotlin
/**
* 网络状态监听测试代码
*/
fun testNetworkStateFlow(context: Context) {
val scope = CoroutineScope(Dispatchers.Main)
scope.launch {
context.networkStateFlow()
.distinctUntilChanged() // 过滤重复状态
.collect { isConnected ->
println(if (isConnected) "网络已连接" else "网络已断开")
}
}
}
3. 🎤 传感器数据监听(Sensor Data)
将传感器回调转换为 Flow:
kotlin
/**
* 将传感器数据回调转换为 Flow
* 持续监听传感器数值变化
*/
fun SensorManager.sensorFlow(sensorType: Int): Flow<SensorEvent> = callbackFlow {
val mSensor = getDefaultSensor(sensorType)
?: throw IllegalArgumentException("Sensor type $sensorType not available")
// 创建传感器监听器
val mSensorListener = object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
// 发送传感器事件
trySend(event)
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
// 精度变化,可根据需求处理
}
}
// 注册传感器监听
registerListener(mSensorListener, mSensor, SensorManager.SENSOR_DELAY_NORMAL)
// Flow 取消时注销监听
awaitClose {
unregisterListener(mSensorListener)
}
}
kotlin
/**
* 传感器监听测试代码
*/
fun testSensorFlow(sensorManager: SensorManager) {
val scope = CoroutineScope(Dispatchers.Default)
scope.launch {
sensorManager.sensorFlow(Sensor.TYPE_ACCELEROMETER)
.collect { event ->
println("X: ${event.values[0]}, Y: ${event.values[1]}, Z: ${event.values[2]}")
}
}
}
4. 🔍 搜索框防抖(SearchView TextWatcher)
将文本变化监听转换为 Flow,实现防抖搜索:
kotlin
/**
* 将 EditText 文本变化监听转换为 Flow
* 配合 debounce 实现防抖搜索
*/
fun EditText.textChangeFlow(): Flow<String> = callbackFlow {
// 创建文本监听器
val mTextWatcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
// 发送当前文本内容
trySend(s?.toString() ?: "")
}
override fun afterTextChanged(s: Editable?) {}
}
// 注册文本监听
addTextChangedListener(mTextWatcher)
// Flow 取消时移除监听
awaitClose {
removeTextChangedListener(mTextWatcher)
}
}
kotlin
/**
* 搜索防抖测试代码
*/
fun testTextChangeFlow(editText: EditText) {
val scope = CoroutineScope(Dispatchers.Main)
scope.launch {
editText.textChangeFlow()
.debounce(300) // 300ms 防抖
.filter { it.isNotEmpty() } // 过滤空字符串
.distinctUntilChanged() // 过滤重复内容
.collect { keyword ->
println("搜索关键词: $keyword")
}
}
}
5. 📷 相机预览帧(Camera2 API)
将 Camera2 的图像回调转换为 Flow:
kotlin
/**
* 将 ImageReader 的图像回调转换为 Flow
* 持续获取相机预览帧数据
*/
fun ImageReader.imageFlow(): Flow<Image> = callbackFlow {
// 设置图像可用监听
val mImageListener = ImageReader.OnImageAvailableListener { reader ->
// 获取最新图像帧并发送
val image = reader.acquireLatestImage()
if (image != null) {
trySend(image)
}
}
// 注册监听器
setOnImageAvailableListener(mImageListener, null)
// Flow 取消时清理资源
awaitClose {
setOnImageAvailableListener(null, null)
}
}
6. 🔵 蓝牙扫描(BLE Scan)
将蓝牙扫描回调转换为 Flow:
kotlin
/**
* 将蓝牙 BLE 扫描回调转换为 Flow
* 持续接收扫描到的蓝牙设备
*/
fun BluetoothLeScanner.scanFlow(): Flow<ScanResult> = callbackFlow {
// 创建扫描回调
val mScanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
// 发送扫描结果
trySend(result)
}
override fun onScanFailed(errorCode: Int) {
// 扫描失败,关闭 Flow
cancel(CancellationException("BLE scan failed, errorCode: $errorCode"))
}
}
// 开始扫描
startScan(mScanCallback)
// Flow 取消时停止扫描
awaitClose {
stopScan(mScanCallback)
}
}
总结对比
| 使用场景 | 传统方式 | callbackFlow 优势 |
|---|---|---|
| 位置监听 | 回调嵌套 | 链式操作,易于组合 |
| 网络状态 | 广播接收器 | 生命周期安全 |
| 传感器数据 | 手动管理注册/注销 | awaitClose 自动清理 |
| 搜索防抖 | 手动实现防抖逻辑 | 配合 debounce 操作符 |
| 蓝牙扫描 | 状态管理复杂 | 结构清晰,易于维护 |
⚠️ 注意事项
- 必须调用
awaitClose:用于清理资源,防止内存泄漏 - 使用
trySend而非send:trySend不会抛出异常,更安全 - 背压处理 :默认缓冲区大小为
Channel.RENDEZVOUS,可通过buffer()操作符调整 - 生命周期绑定 :建议配合
lifecycleScope或viewModelScope使用,避免泄漏