skip to content
Posts · February 2024

BaseViewModel with STATE


abstract class BaseViewModel<STATE: Parcelable>(
private val savedStateHandle: SavedStateHandle,
private val defaultState: STATE
): ViewModel() {
private val KEY_STATE = "state"
val state: StateFlow<STATE> = savedStateHandle.getStateFlow(KEY_STATE, defaultState)
protected fun updateState(newState: STATE.() -> STATE) {
// see DataStore updateData
// get current state
savedStateHandle.get<STATE>(KEY_STATE)?.let { state ->
// simpan state baru ke savedStateHandle
savedStateHandle[KEY_STATE] = newState(state)
}
}
}
@Parcelize
data class MyState(
val text: String = ""
): Parcelable
@HiltViewModel
class MyViewModel @Inject constructor(
savedStateHandle: SavedStateHandle
): BaseViewModel<MyState>(
savedStateHandle = savedStateHandle,
defaultState = MyState()
) {
fun updateText(newText: String) {
updateState {
copy(
text = newText
)
}
}
}
@Composable
fun MyScreen(
viewModel: MyViewModel = hiltViewModel()
) {
// Observe state
val state by viewModel.state.collectAsStateWithLifecycle()
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
) {
OutlinedTextField(
value = state.text,
onValueChange = viewModel::updateText
)
}
}
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeResearchTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
MyScreen()
}
}
}
}
}