1

Is there a way to initialize a MutableStateFlow with data obtained from a database? I tried the following approach, but the recordedActivityUiState is not updated with the object from the activitiesRepository.

val recordedActivityUiState = MutableStateFlow(ActivityUiState())
// State used only to update the recordedActivity UI state
val recordedActivityState = activitiesRepository.getRecordedActivity().map { recordedActivity ->
    if (recordedActivity != null) {
        recordedActivityUiState.update {
            ActivityUiState(
                id = recordedActivity.id,
                title = recordedActivity.title,
                note = recordedActivity.note,
                startTime = recordedActivity.startTime
            )
        }
    }
}

1 Answer 1

0

Your code doesn't work because you never applied a terminal operator to the flow, like collect(). Only then map would be executed.

The following assumes the code is placed in a view model.

If you only want to ever execute the code once as long as the view model lives, you can use something like this instead:

private val _recordedActivityUiState = MutableStateFlow(ActivityUiState())
val recordedActivityUiState: StateFlow<ActivityUiState> = _recordedActivityUiState.asStateFlow()

init {
    viewModelScope.launch {
        activitiesRepository.getRecordedActivity().first()?.also { recordedActivity ->
            _recordedActivityUiState.value = ActivityUiState(
                id = recordedActivity.id,
                title = recordedActivity.title,
                note = recordedActivity.note,
                startTime = recordedActivity.startTime,
            )
        }
    }
}

fun updateTitle(title: String) {
    _recordedActivityUiState.update {
        it.copy(title = title)
    }
}

The init block is executed once during object creation. If you need it to be executed multiple times, move it to a function instead. The above code also takes care of the issue that you exposed the MutableStateFlow as a public property. You shouldn't do that, instead convert it to a read-only StateFlow and add update functions that are used to internally modify the MutableStateFlow.

When first() is applied to the database flow it collects the flow and stops after the first value was received. The flow will emit new values whenever something changes in the database, so your app would always be up to date. But by truncating the flow after the first value you throw out the main advantage of the flow. In this case you shouldn't even use flows.

However, if you actually do want to always have the current database value around, then you need to refactor your code:

val recordedActivityUiState: StateFlow<ActivityUiState> = activitiesRepository.getRecordedActivity()
    .map { recordedActivity ->
        if (recordedActivity == null) ActivityUiState()
        else ActivityUiState(
            id = recordedActivity.id,
            title = recordedActivity.title,
            note = recordedActivity.note,
            startTime = recordedActivity.startTime,
        )
    }
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5.seconds),
        initialValue = ActivityUiState(),
    )

fun updateTitle(title: String) {
    viewModelScope.launch {
        activitiesRepository.updateRecordedActivity(
            // ...
        )
    }
}

Now the database flow is directly plugged in the recordedActivityState property and converted to a StateFlow using stateIn(). Is is not mutable, however, so if you want to change anything, you have to change the database itself. This is how you should usually handle database content. You should only have a Single Source of Truth for each piece of data in your app, and no intermediate values that can grow stale over time.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.