initialState

abstract override fun initialState(props: PropsT, snapshot: Snapshot?, workflowScope: CoroutineScope): StateT(source)

Parameters

workflowScope

A CoroutineScope that has been created when this Workflow is first rendered and canceled when it is no longer rendered.

This CoroutineScope can be used to:

  • own the transforms on a StateFlow, linking them to the lifetime of a Workflow session. For example, here is how you might safely combine two StateFlows:

     data class MyState(
          val derivedValue: String,
          val derivedWorker: Worker
        )
    
        override fun initialState(
          props: Unit,
          snapshot: Snapshot?,
          workflowScope: CoroutineScope
        ): MyState {
          val transformedStateFlow = stateFlow1.combine(stateFlow2, {val1, val2 -> val1 - val2}).
            stateIn(workflowScope, SharingStarted.Eagerly, ${stateFlow1.value}-${stateFlow2.value})
    
          return MyState(
            transformedStateFlow.value,
            transformedStateFlow.asWorker()
          )
        }
  • set reliable teardown hooks, e.g. via Job.invokeOnCompletion. Note however, that while these are reliable in the sense of being guaranteed to be executed regardless of the lifetime of this workflow session, they are not reliable in that a completion handler on the Job is not thread-safe and will be executed on whatever the last dispatcher was used when the Job completes. See more on the Job.invokeOnCompletion kdoc.

    So what do you do? Well, cleanup and lifecycle matters should be handled by each individual Worker and sideEffect. Consider using a try { } finally { cleanup() } or Flow.onCompletion to handle that.

    If you have a general cleanup operation that is fast and thread-safe then you could use Job.invokeOnCompletion. Otherwise use awaitCancellation with a finally block. Examples:

      override fun initialState(
          props: Unit,
          snapshot: Snapshot?,
          workflowScope: CoroutineScope
        ): MyState {
          someService.start()
          workflowScope.coroutineContext.job.invokeOnCompletion {
            // If quick and does not need to execute on the Workflow runtime's thread.
            someService.stop()
          }
          workflowScope.launch(start = CoroutineStart.UNDISPATCHED) {
            try {
              awaitCancellation()
            } finally {
              // If should be executed on the Workflow runtime's thread.
              someService.stop()
            }
          }
          return MyState()
        }

Note Carefully: Neither workflowScope nor any of these transformed/computed dependencies should be stored by this Workflow instance. This could be re-created, or re-used unexpectedly and should not have its own state. Instead, the transformed/computed dependencies must be put into the StateT of this Workflow in order to be properly maintained.

See also

for kdoc on the base function of this method.

This version adds the following:


override fun initialState(props: PropsT, snapshot: Snapshot?): StateT(source)

Do not use this in favor of the version of initialState above that includes the Workflow's CoroutineScope