| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
A small Android learning app that shows where form state actually lives, and which of those stores survive:
You fill in Name, Email, and Notes, then try to kill the UI in different ways. The State Inspector on the screen tells you whether the values came from the ViewModel, SavedStateHandle, or DataStore.
This is not a production form. It is a lab for Android lifecycle and state.
Android can throw away your UI without the user meaning to:
Those are different events. They need different stores.
| Store | Used for | Survives | Does not survive |
|---|---|---|---|
| remember | UI chrome only (section open/closed) | Recomposition | Rotation, process death |
| ViewModel + StateFlow | Live form on screen | Recomposition, rotation | Process death |
| SavedStateHandle | Unsaved draft | Process death if you return from Recents | Force Stop, Run, swipe-away Recents |
| DataStore | Permanent save | Force Stop, new launch, reboot | Nothing, until the user taps Save Permanently |
Two ideas the app keeps separate on purpose:
Clear Form clears the draft only. DataStore still has the last permanent save. Close the app fully and reopen: the saved form comes back.
Simulate Process Death cannot kill the process the way Android does. It flushes the draft and points you at Test 3. Use Logcat Terminate Application or adb shell am kill for a real kill.
FormScreen (Compose, stateless)
↓ events up, FormUiState down
FormViewModel (StateFlow + SavedStateHandle)
↓ only on Save Permanently / launch restore
FormRepository
↓
FormDataStore (Preferences DataStore)
The screen never talks to DataStore. The ViewModel never talks to the file API directly.
Build and run the app module on a device or emulator (com.processdeath.app). After each test, read the State Inspector at the bottom of the screen.
The same steps are inside the app under How to Test.
Goal: Prove the form does not live in the composition.
Why it survives: The form is in the ViewModel StateFlow, outside Compose. Redrawing the UI does not recreate the ViewModel.
remember would also survive recomposition, but this app does not store Name / Email / Notes there. Those flags are only “is this section open?”
Goal: Prove ViewModel outlives the Activity.
Why the form survives: The Activity is destroyed and recreated. The ViewModelStore is kept, so the new Activity gets the same ViewModel.
Why the sections close: Their expand state is remember. That dies with the composition.
Goal: Prove SavedStateHandle can restore a draft after the process is gone.
Verify: Fields come back. Inspector says this session loaded from SavedStateHandle.
Limits of SavedStateHandle:
Do not use this button as a real kill. An app cannot reliably simulate system process death by calling killProcess on itself.
Goal: Prove DataStore is the “I meant to keep this” path.
Verify: Fields come back. Inspector says this session loaded from DataStore.
Why DataStore: You asked to persist the form. That belongs on disk, not in a task-scoped bundle. Preferences DataStore is a file API for a few key-value fields. Room would be for a table of rows.
| Action | Skip Save, then kill | Save, then Force Stop |
|---|---|---|
| Recents restore after am kill | Draft from SavedStateHandle | Same values, but source was disk if it was a new task |
| Force Stop / Run / new task | Empty, or last permanent save if you had one | Form from DataStore |
com.processdeath.app
├── MainActivity.kt Hosts ViewModel, collects StateFlow
├── ui
│ ├── FormScreen.kt Stateless UI + inspector + test guide
│ ├── FormViewModel.kt Draft + restore rules
│ └── FormUiState.kt Immutable snapshot
└── data
├── FormRepository.kt ViewModel → disk boundary
└── FormDataStore.kt Preferences DataStore
| Back | FazBrowse Home | New Git URL |