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

Kotlin Flows如何在首订阅和末退订时自动执行位置更新启停逻辑

解决方案

可以直接使用Kotlin协程Flow自带的shareIn操作符配合SharingStarted.WhileSubscribed()实现需求,完全不需要手动维护订阅计数器,系统实现已经内置了订阅数自动统计逻辑,比手动计数更稳定,也能避免并发场景下的计数异常问题。

实现步骤

  • 第一步:将FusedLocationProvider的位置回调封装为callbackFlow,冷流特性可以保证只有订阅时才会启动位置更新,流取消时自动停止更新
  • 第二步:使用shareIn操作符将冷流转换为共享热流,指定SharingStarted.WhileSubscribed()作为启动策略,即可实现「首个订阅者出现时启动上游流,最后一个订阅者退出时关闭上游流」的逻辑
  • 可配置WhileSubscribed的stopTimeoutMillis参数,设置最后一个订阅者退出后延迟停止位置更新的时长,避免页面横竖屏切换等短时间退订再订阅的场景触发频繁启停

优化后完整代码

@Singleton
class LocationRepository @Inject constructor(
    app: Application
) {
    // 绑定仓库生命周期的协程作用域,单例场景下和App生命周期一致
    private val repositoryScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
    private val client = LocationServices.getFusedLocationProviderClient(app)
    private val request = LocationRequest.create().apply {
        priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
        interval = 5000L
        fastestInterval = 2500L
    }

    val location: Flow<Location?> = callbackFlow {
        // 位置回调实现
        val locCb = object : LocationCallback() {
            override fun onLocationResult(var1: LocationResult?) {
                var1?.lastLocation?.let { trySend(it) }
            }
            override fun onLocationAvailability(var1: LocationAvailability) {}
        }
        // 启动位置更新
        client.requestLocationUpdates(request, locCb, Looper.getMainLooper())
        // 流取消时自动移除回调、停止更新
        awaitClose {
            client.removeLocationUpdates(locCb)
        }
    }
    // 配置共享流策略
    .shareIn(
        scope = repositoryScope,
        // 最后一个订阅者退出后延迟3s再停止,避免频繁启停
        started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 3000),
        // 新订阅者可以拿到最新的1条位置数据,和原StateFlow行为一致
        replay = 1
    )
}

方案说明

  • 对外暴露的location流接口和原有实现完全一致,调用侧不需要做任何修改
  • 不需要手动维护AtomicInteger计数,也不需要额外配置onSubscription/onCompletion回调,所有订阅管理逻辑由系统内置实现处理
  • callbackFlow的awaitClose块可以保证位置回调一定会被移除,不会出现内存泄漏问题

如果你的需求必须保留原有MutableStateFlow的实现,也可以直接使用stateIn操作符替代手动维护的_location变量,stateIn同样支持SharingStarted.WhileSubscribed()策略,逻辑和上述shareIn完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 00:36:04