在 Kotlin 协程中,StateFlow 和 SharedFlow 确实是最常用的两种可共享的热流(Hot Flow),它们都是 SharedFlow 的子类,你截图里的新旧代码对比正好就是它们的典型用法。下面为你系统梳理二者的区别、适用场景及核心注意事项,结尾附上可直接复用的网络状态监听工具类示例。
1. 基础概念:冷流 vs 热流
-
冷流(Cold Flow):比如最基础的 flow { ... },它是"懒加载"的,只有当有 Collector(收集者)订阅时才会开始发射数据,每个 Collector 都会触发一次独立的数据生产,订阅者之间互不影响。
-
热流(Hot Flow):SharedFlow 和 StateFlow 都属于热流,其数据生产与订阅行为解耦,不管有没有 Collector 订阅,都会持续生产数据(或维护状态),所有订阅者共享同一套数据,确保数据一致性。
2. SharedFlow:通用的多播热流
-
核心特点:
-
可配置缓存策略:通过 replay 参数设置缓存历史数据条数,新订阅者会优先接收缓存数据;extraBufferCapacity 用于设置额外缓冲区大小,应对突发发射场景。
-
无初始值约束:仅在调用 emit() 或 tryEmit() 时才会发射数据,未发射数据前无默认值可用。
-
多播特性:支持多个订阅者同时接收数据,数据发射一次可被所有订阅者捕获。
-
-
适用场景:
-
事件通知类场景:如按钮点击事件、网络请求结果回调、消息推送、日志上报等。
-
无需维护当前状态:仅需广播一次性事件,无需订阅者获取"最新快照"的场景。
-
代码示例:
kotlin
private val _networkState = MutableSharedFlow<Boolean>(extraBufferCapacity = 1)
val networkChangedFlow = _networkState.asSharedFlow()
通过 extraBufferCapacity = 1 配置额外缓冲区大小为1,可避免发射数据时因无订阅者导致阻塞,同时让新订阅者能接收最近1条缓存数据,确保状态不丢失。
3. StateFlow:持有单一状态的 SharedFlow
-
核心特点:
-
强状态绑定:是 SharedFlow 的特殊实现,专门用于持有和维护单一"当前状态值",本质等价于 SharedFlow(replay = 1, extraBufferCapacity = 0) 并自动过滤重复值。
-
必须指定初始值:创建 MutableStateFlow 时需传入初始值,确保任何时候订阅者都能获取到状态(即使未更新过)。
-
自动去重与即时同步:更新状态时,仅当新值与旧值不相等才会发射数据,避免无效刷新;新订阅者订阅后会立即收到当前最新状态值。
-
-
适用场景:
-
状态管理类场景:如网络连接状态、用户登录状态、UI 控件状态(开关、进度)、页面数据缓存等。
-
需实时获取最新状态:订阅者不仅要监听状态变化,还需随时获取当前快照的场景。
-
-
代码示例:
kotlin
private val _networkState = MutableStateFlow<Boolean?>(null)
val networkChangedFlow = _networkState.asStateFlow()
这里用 null 作为初始值,代表网络状态初始未知;后续通过 _networkState.value = true/false 更新状态(连接/断开),订阅者会实时收到变化通知并获取最新状态。
4. 核心对比与使用注意事项
4.1 核心维度对比

4.2 关键使用注意事项
-
线程安全问题:MutableStateFlow 和 MutableSharedFlow 的 emit() 方法需在协程中调用,tryEmit() 可在非协程环境使用(返回布尔值表示发射结果),二者均支持多线程并发更新,无需额外加锁。
-
订阅生命周期管理:在 Android 等平台使用时,需绑定页面/组件生命周期(如 lifecycleScope.launchWhenStarted),避免内存泄漏;订阅后若无需监听,可调用 Job.cancel() 手动取消。
-
状态暴露规范:对外暴露不可变流(asStateFlow()/asSharedFlow()),仅在内部保留可变流(MutableXXXFlow)的修改权限,确保状态可控,避免外部随意篡改。
-
SharedFlow 缓存配置:避免过度设置 replay 大小,否则会占用额外内存;若仅需新订阅者接收最新一条数据,设置 replay = 1 即可,无需额外缓冲区。
5. 实战示例:StateFlow 实现网络状态监听工具类
结合上文内容,以下是基于 StateFlow 实现的网络状态监听工具类,适配 Android 平台,支持监听网络连接/断开状态,可直接集成到项目中使用:
kotlin
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Build
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
/**
* 网络状态监听工具类(基于 StateFlow 实现)
* 支持监听网络连接状态,对外暴露不可变流,确保状态安全
*/
class NetworkMonitor private constructor(private val context: Context) {
// 可变状态流(内部修改),初始值为 null(未知状态)
private val _networkState = MutableStateFlow<Boolean?>(null)
// 不可变状态流(对外暴露),供外部订阅
val networkState: StateFlow<Boolean?> = _networkState.asStateFlow()
// 可选:转为 LiveData 适配传统生命周期组件
val networkLiveData: LiveData<Boolean?> = networkState.asLiveData()
private val connectivityManager by lazy {
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}
// 网络回调,监听网络状态变化
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
// 网络可用,更新状态为 true
_networkState.value = true
}
override fun onLost(network: Network) {
super.onLost(network)
// 网络断开,检查是否还有其他可用网络
_networkState.value = isNetworkAvailable()
}
override fun onUnavailable() {
super.onUnavailable()
// 网络不可用,更新状态为 false
_networkState.value = false
}
}
/**
* 初始化监听
*/
fun startMonitoring() {
// 初始获取一次网络状态
_networkState.value = isNetworkAvailable()
// 注册网络监听回调
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
connectivityManager.registerDefaultNetworkCallback(networkCallback)
} else {
// 适配低版本系统
val request = android.net.NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(request, networkCallback)
}
}
/**
* 停止监听,避免内存泄漏
*/
fun stopMonitoring() {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
/**
* 主动检查当前网络是否可用
*/
private fun isNetworkAvailable(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
} else {
// 低版本兼容
val networkInfo = connectivityManager.activeNetworkInfo ?: return false
return networkInfo.isConnected && networkInfo.isAvailable
}
}
// 单例模式,确保全局唯一实例
companion object {
@Volatile
private var instance: NetworkMonitor? = null
fun getInstance(context: Context): NetworkMonitor {
return instance ?: synchronized(this) {
instance ?: NetworkMonitor(context.applicationContext).also { instance = it }
}
}
}
}
示例使用方式
在 Android Activity/Fragment 中订阅网络状态,绑定生命周期避免内存泄漏:
kotlin
// 在 Activity 中初始化
class MainActivity : AppCompatActivity() {
private lateinit var networkMonitor: NetworkMonitor
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 初始化网络监听工具
networkMonitor = NetworkMonitor.getInstance(applicationContext)
// 启动监听
networkMonitor.startMonitoring()
// 订阅网络状态(使用 lifecycleScope 绑定生命周期)
lifecycleScope.launchWhenStarted {
networkMonitor.networkState.collect { isConnected ->
when (isConnected) {
true -> {
// 网络已连接,更新 UI 或执行相关逻辑
tvNetworkStatus.text = "网络已连接"
}
false -> {
// 网络已断开,提示用户或执行离线逻辑
tvNetworkStatus.text = "网络已断开"
}
null -> {
// 初始未知状态,可显示加载中
tvNetworkStatus.text = "正在检查网络状态..."
}
}
}
}
}
override fun onDestroy() {
super.onDestroy()
// 停止监听,释放资源
networkMonitor.stopMonitoring()
}
}
该示例优势:基于 StateFlow 确保状态实时同步和自动去重,避免 UI 无效刷新;适配高低版本 Android 系统,提供单例模式和生命周期管理,兼顾安全性与实用性。