architecture-samples icon indicating copy to clipboard operation
architecture-samples copied to clipboard

[main] User input for add/edit screen is lost across process death

Open Zhuinden opened this issue 3 years ago • 2 comments

Similarly to older issues that have since been either closed or fixed such as https://github.com/android/architecture-samples/issues/370 and https://github.com/android/architecture-samples/issues/123 and https://github.com/android/architecture-samples/issues/731 and https://github.com/android/architecture-samples/issues/663

This bug seems to have been long-standing, but with MutableStateFlow(UiState) it still persists - as on this screen, SavedStateHandle is used only for transferring screen arguments to the ViewModel, but is not actually used to preserve user inputs across process death.

https://github.com/android/architecture-samples/blob/7e9d96d808a0d25a689d14099ecf0eb3ea7d5b1f/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskViewModel.kt#L39-L40


On the other hand, TasksViewModel correctly persists the current filter state using savedStateHandle.getStateFlow.

https://github.com/android/architecture-samples/blob/7e9d96d808a0d25a689d14099ecf0eb3ea7d5b1f/app/src/main/java/com/example/android/architecture/blueprints/todoapp/tasks/TasksViewModel.kt#L64-L65

Filtering state on the tasks screen was originally fixed by setting it on the SavedStateHandle in this commit: https://github.com/android/architecture-samples/commit/cfb5ac6ea6a5c888b171d88d7ea4287a33af5cb9#diff-631edb6efa01767b52856a0e498dc3987e8a2f0e8ba02837377dfbc5684af0cfR111


Therefore, AddEdit screen should also correctly save/restore user inputs across process death.

Zhuinden avatar Dec 06 '22 10:12 Zhuinden

Solution To fix this, you should persist the input fields (title, description) using SavedStateHandle, the same way it's done for filters in TasksViewModel.

How to Fix It in AddEditTaskViewModel.kt Update your ViewModel like this:

class AddEditTaskViewModel( private val savedStateHandle: SavedStateHandle ) : ViewModel() {

companion object {
    private const val TITLE_KEY = "title"
    private const val DESCRIPTION_KEY = "description"
}

// Use getStateFlow to keep track and survive process death
val title = savedStateHandle.getStateFlow(TITLE_KEY, "")
val description = savedStateHandle.getStateFlow(DESCRIPTION_KEY, "")

fun onTitleChanged(newTitle: String) {
    savedStateHandle[TITLE_KEY] = newTitle
}

fun onDescriptionChanged(newDescription: String) {
    savedStateHandle[DESCRIPTION_KEY] = newDescription
}

// Save state or clear based on whether the task is saved/cancelled
fun onTaskSaved() {
    // Handle saving the task, then optionally clear:
    savedStateHandle.remove(TITLE_KEY)
    savedStateHandle.remove(DESCRIPTION_KEY)
}

} UI Binding Changes Make sure your Composable or Fragment binds to title and description from ViewModel.title.collectAsState() and calls onTitleChanged() when the user types.

Why This Works SavedStateHandle persists values across process death.

getStateFlow provides a lifecycle-safe, observable wrapper.

Works even if your ViewModel is re-instantiated due to system constraints.

TL;DR Fix Summary Replace plain MutableStateFlow usage with savedStateHandle.getStateFlow(...), and update the values with savedStateHandle[KEY] = newValue. This will ensure user input on the Add/Edit screen is retained after process death just like the filtering state was fixed before.

Let me know if you want a working patch or pull request code format.

VaradGupta23 avatar Jul 16 '25 04:07 VaradGupta23

Correct answer

Zhuinden avatar Jul 17 '25 23:07 Zhuinden