@@ -26,8 +26,8 @@ import androidx.annotation.VisibleForTesting
2626import androidx.annotation.VisibleForTesting.PRIVATE
2727import androidx.compose.Composable
2828import androidx.compose.Direct
29- import androidx.compose.Pivotal
3029import androidx.compose.State
30+ import androidx.compose.key
3131import androidx.compose.onDispose
3232import androidx.compose.remember
3333import androidx.compose.state
@@ -275,58 +275,60 @@ import kotlin.coroutines.CoroutineContext
275275 * the [UiSavedStateRegistryAmbient]. If null, will use the default key based on source location.
276276 */
277277@Composable private fun <PropsT , OutputT : Any , RenderingT > renderAsState (
278- @Pivotal workflow : Workflow <PropsT , OutputT , RenderingT >,
278+ workflow : Workflow <PropsT , OutputT , RenderingT >,
279279 props : PropsT ,
280280 onOutput : (OutputT ) -> Unit ,
281- @Pivotal coroutineContext : CoroutineContext ,
282- @Pivotal diagnosticListener : WorkflowDiagnosticListener ? ,
281+ coroutineContext : CoroutineContext ,
282+ diagnosticListener : WorkflowDiagnosticListener ? ,
283283 snapshotKey : String?
284284): State <RenderingT > {
285- // This can be a StateFlow once coroutines is upgraded to 1.3.6.
286- val propsChannel = remember { Channel <PropsT >(capacity = CONFLATED ) }
287- propsChannel.offer(props)
285+ key(workflow, coroutineContext, diagnosticListener) {
286+ // This can be a StateFlow once coroutines is upgraded to 1.3.6.
287+ val propsChannel = remember { Channel <PropsT >(capacity = CONFLATED ) }
288+ propsChannel.offer(props)
289+
290+ // Need a mutable holder for onOutput so the outputs subscriber created in the onActive block
291+ // will always be able to see the latest value.
292+ val outputCallback = remember { OutputCallback (onOutput) }
293+ outputCallback.onOutput = onOutput
288294
289- // Need a mutable holder for onOutput so the outputs subscriber created in the onActive block
290- // will always be able to see the latest value.
291- val outputCallback = remember { OutputCallback (onOutput) }
292- outputCallback.onOutput = onOutput
295+ val renderingState = state<RenderingT ?> { null }
296+ val snapshotState = savedInstanceState(key = snapshotKey, saver = SnapshotSaver ) { null }
293297
294- val renderingState = state<RenderingT ?> { null }
295- val snapshotState = savedInstanceState(key = snapshotKey, saver = SnapshotSaver ) { null }
298+ // We can't use onActive/on(Pre)Commit because they won't run their callback until after this
299+ // function returns, and we need to run this immediately so we get the rendering synchronously.
300+ val workflowScope = remember {
301+ val coroutineScope = CoroutineScope (coroutineContext + Dispatchers .Main .immediate)
302+ val propsFlow = propsChannel.consumeAsFlow()
303+ .distinctUntilChanged()
296304
297- // We can't use onActive/on(Pre)Commit because they won't run their callback until after this
298- // function returns, and we need to run this immediately so we get the rendering synchronously.
299- val workflowScope = remember {
300- val coroutineScope = CoroutineScope (coroutineContext + Dispatchers .Main .immediate)
301- val propsFlow = propsChannel.consumeAsFlow()
302- .distinctUntilChanged()
305+ launchWorkflowIn(coroutineScope, workflow, propsFlow, snapshotState.value) { session ->
306+ session.diagnosticListener = diagnosticListener
303307
304- launchWorkflowIn(coroutineScope, workflow, propsFlow, snapshotState.value) { session ->
305- session.diagnosticListener = diagnosticListener
308+ // Don't call onOutput directly, since out captured reference won't be changed if the
309+ // if a different argument is passed to observeWorkflow.
310+ session.outputs.onEach { outputCallback.onOutput(it) }
311+ .launchIn(this )
306312
307- // Don't call onOutput directly, since out captured reference won't be changed if the
308- // if a different argument is passed to observeWorkflow.
309- session.outputs.onEach { outputCallback.onOutput(it) }
310- .launchIn(this )
313+ session.renderingsAndSnapshots
314+ .onEach { (rendering, snapshot) ->
315+ renderingState.value = rendering
316+ snapshotState.value = snapshot
317+ }
318+ .launchIn(this )
319+ }
311320
312- session.renderingsAndSnapshots
313- .onEach { (rendering, snapshot) ->
314- renderingState.value = rendering
315- snapshotState.value = snapshot
316- }
317- .launchIn(this )
321+ return @remember coroutineScope
318322 }
319323
320- return @remember coroutineScope
321- }
324+ onDispose {
325+ workflowScope.cancel()
326+ }
322327
323- onDispose {
324- workflowScope.cancel()
328+ // The value is guaranteed to be set before returning, so this cast is fine.
329+ @Suppress(" UNCHECKED_CAST" )
330+ return renderingState as State <RenderingT >
325331 }
326-
327- // The value is guaranteed to be set before returning, so this cast is fine.
328- @Suppress(" UNCHECKED_CAST" )
329- return renderingState as State <RenderingT >
330332}
331333
332334private object SnapshotSaver : Saver<Snapshot?, ByteArray> {
0 commit comments