一、produceState 是 Compose Runtime 提供的一个 Composable 函数,它的核心作用是把非 Compose 的外部数据源(如 Flow、LiveData、回调、轮询等)转换成 Compose 可观察的 State。
kotlin
@Composable
fun <T> produceState(
initialValue: T,
vararg keys: Any?,
producer: suspend ProduceStateScope<T>.() -> Unit
): State<T>
关键特性 1、自动生命周期管理:producer 协程在 produceState 进入组合时启动,离开组合时自动取消 2、Key 驱动重启:当 keys 参数发生变化时,正在运行的 producer 会被取消并重新启动 3、值合并(Conflation):如果连续设置的新值与旧值 equals 相等,不会触发重组
例子
kotlin
sealed class Result<out T> {
object Loading : Result<Nothing>()
data class Success<T>(val data: T) : Result<T>()
data class Error(val exception: Throwable) : Result<Nothing>()
}
// 加载网络图片
@Composable
fun loadNetworkImage(url: String): State<Result<Bitmap>> {
return produceState<Result<Bitmap>>(
initialValue = Result.Loading,
key1 = url // url 变化时重新加载
) {
value = try {
Result.Success(loadImage(url))
} catch (e: Exception) {
Result.Error(e)
}
}
}
// 在 Composable 中使用
@Composable
fun ImageScreen(imageUrl: String) {
// 调用 produceState,拿到 State<Result<ImageBitmap>>
val imageState by loadNetworkImage(imageUrl)
// 根据状态渲染不同 UI
when (val result = imageState) {
is Result.Loading -> {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
CircularProgressIndicator() // 加载中,显示转圈
}
}
is Result.Success -> {
Image(
bitmap = result.data,
contentDescription = "网络图片",
modifier = Modifier.fillMaxWidth()
)
}
is Result.Error -> {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text("加载失败: ${result.exception.message}")
}
}
}
}
// 监听网络状态
@Composable
fun observeConnectivity(): State<Boolean> {
val context = LocalContext.current
return produceState(initialValue = false) {
val manager = context.getSystemService<ConnectivityManager>()!!
val callback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) { value = true }
override fun onLost(network: Network) { value = false }
}
manager.registerDefaultNetworkCallback(callback)
// 离开组合时自动清理
awaitDispose { manager.unregisterNetworkCallback(callback) }
}
}
一句话总结:把任何异步/回调式的数据源"桥接"进 Compose 的响应式世界。
二、produceState 实现与在ViewModel实现对比 方式一:produceState 写在 Composable(轻量场景)
kotlin
@Composable
fun ImageScreen(imageUrl: String) {
val imageState by loadNetworkImage(imageUrl) // produceState 在这里
when (val result = imageState) {
is Result.Loading -> CircularProgressIndicator()
is Result.Success -> Image(bitmap = result.data, ...)
is Result.Error -> Text("加载失败")
}
}
优点:代码短、零样板、逻辑和 UI 在一个文件里,适合简单页面或原型。
缺点: 无法被多个 Composable 共享同一份加载状态 配置变更(旋转屏幕)时协程会被取消重建,数据可能丢失 不方便做单元测试(耦合在 Composable 里)
方式二:使用 ViewModel
kotlin
class ImageViewModel : ViewModel() {
private val _imageState = MutableStateFlow<Result<ImageBitmap>>(Result.Loading)
val imageState: StateFlow<Result<ImageBitmap>> = _imageState.asStateFlow()
private var loadJob: Job? = null
fun loadImage(url: String) {
loadJob?.cancel()
loadJob = viewModelScope.launch {
_imageState.value = Result.Loading
_imageState.value = try {
Result.Success(loadImageFromUrl(url))
} catch (e: Exception) {
Result.Error(e)
}
}
}
}
@Composable
fun ImageScreen(viewModel: ImageViewModel = viewModel()) {
val imageState by viewModel.imageState.collectAsStateWithLifecycle()
when (val result = imageState) {
is Result.Loading -> CircularProgressIndicator()
is Result.Success -> Image(bitmap = result.data, ...)
is Result.Error -> Text("加载失败")
}
}
优点: ViewModel 存活,数据不丢,不用重新请求 多个 Composable 订阅同一个 StateFlow 测试 ViewModel 可以脱离 UI 做单元测试 生命周期 viewModelScope 跟随 ViewModel,不影响 Composable 重组
三、原理 核心源码
kotlin
@Composable
fun <T> produceState(
initialValue: T,
vararg keys: Any?,
producer: suspend ProduceStateScope<T>.() -> Unit
): State<T> {
// ① remember 持有一个可变状态
val result = remember { mutableStateOf(initialValue) }
// ② LaunchedEffect 在协程中执行 producer
LaunchedEffect(keys = keys) {
ProduceStateScopeImpl(result, coroutineContext).producer()
}
// ③ 返回只读 State
return result
}
producer 代码块的接收者类型是 ProduceStateScope
kotlin
producer: suspend ProduceStateScope<T>.() -> Unit
suspend ← 这是个挂起函数
ProduceStateScope<T>. ← 接收者类型(receiver type)
() -> Unit ← 无参数,返回 Unit
含义:producer 是一个挂起函数,它没有显式参数,但它有一个隐式的 this,类型是 ProduceStateScope<T>。
kotlin
interface ProduceStateScope<T> : MutableState<T>, CoroutineScope {
suspend fun awaitDispose(onDispose: () -> Unit): Nothing
}
internal class ProduceStateScopeImpl<T>(
state: MutableState<T>,
override val coroutineContext: CoroutineContext
) : ProduceStateScope<T>, MutableState<T> by state {
override suspend fun awaitDispose(onDispose: () -> Unit): Nothing {
try {
// 永久挂起,直到协程被取消
suspendCancellableCoroutine<Nothing> {}
} finally {
onDispose() // 协程取消时在 finally 中执行清理
}
}
}
一句话总结
scss
produceState = remember { mutableStateOf() } + LaunchedEffect { producer() } + 一个包装了 State 和 CoroutineScope 的作用域对象。
它没有引入任何新的底层机制,只是把"创建状态 + 协程异步更新 + 生命周期绑定 + 清理"这套常见组合封装成了一个简洁的 API。