Android75
04/14/2021, 3:03 AMopen class BaseViewModel<State : Any, Event : Any> : ViewModel() {
private val stateLiveData: MutableLiveData<State> = MutableLiveData()
and now with StateFlow:
open class BaseFlowViewModel<State : Any, Event : Any> : ViewModel() {
private val _uiState = MutableStateFlow<State>()
val uiState: StateFlow<State> = _uiState
MutableStateFlow<State>() wants a parameter... what can i put as paramter?Casey Brooks
04/14/2021, 3:09 AMKamilH
04/14/2021, 3:09 AMMutableStateFlow
has always value
, so it needs initial value, so you need to pass it when initializing. I would suggest to make your BaseViewModel
accept initialState
, that you will then pass to MutableStateFlow
"constructor"Android75
04/14/2021, 3:15 AMprivate val _uiState = MutableStateFlow<State>( Any() as State)
Android75
04/14/2021, 3:15 AMCasey Brooks
04/14/2021, 3:18 AMAny
to State
will crash. You need to create an instance of State
with default values that represent “the state of your screen before you’ve started loading or changing anything”.
Typically, I make sure my State
class has default values for all its constructor parameters, so that I can simply do MutableStateFlow<State>(State())
in my ViewModel, and leave the “uninitialized-state values” as a concern of the State
class itselfAndroid75
04/14/2021, 3:28 AMAndroid75
04/14/2021, 3:28 AMephemient
04/14/2021, 3:32 AMMutableStateFlow<State?>(null)
and .filterNotNull()
for clientsAndroid75
04/14/2021, 3:33 AMIan Lake
04/14/2021, 3:33 AMMutableSharedFlow
, which is a MutableStateFlow
without the state
Casey Brooks
04/14/2021, 3:35 AMBaseFlowViewModel
a constructor parameter of that initial state. Subclasses must provide the initial value themselves
open class BaseFlowViewModel<State : Any, Events : Any> : ViewModel() {
private val _uiState = MutableStateFlow<State>()
}
class Screen1ViewModel : BaseFlowViewModel<Screen1ViewModel.State, Screen1ViewModel.Events>(Screen1ViewModel.State()) {
data class State(
val loading: Boolean = false,
val intValue: Int = 0,
)
sealed class Events {
object GoToScreen2 : Events()
}
}
Android75
04/14/2021, 3:35 AMAndroid75
04/14/2021, 3:37 AMAndroid75
04/14/2021, 4:42 AMAndroid75
04/14/2021, 4:42 AMopen class BaseFlowViewModel<State : Any, Event : Any> : ViewModel() {
val _uiState = MutableStateFlow<State?>(null)
val uiState: StateFlow<State?> = _uiState
Android75
04/14/2021, 4:42 AMAndroid75
04/14/2021, 4:43 AMAndroid75
04/14/2021, 4:43 AMabstract class BaseFlowActivityViewBinding<State : Any, Event : Any>() : AppCompatActivity() {
Android75
04/14/2021, 4:43 AMlifecycleScope.launchWhenStarted {
provideBaseViewModel().uiState.collect { uiState ->
handleUiState(uiState)
}
}
Android75
04/14/2021, 4:44 AMoverride fun handleUiState(state: MainState?) {
when(state){
is MainState.Print ->{
Log.i("asarch", " PRINT")
}
}
}
Android75
04/14/2021, 4:48 AMephemient
04/14/2021, 5:42 AMIan Lake
04/14/2021, 6:01 AMstateLiveData.value
before that initial value, you'd get null
Ian Lake
04/14/2021, 6:03 AMreceiveAsFlow()
to process them as per https://elizarov.medium.com/shared-flows-broadcast-channels-899b675e805c#49e3Android75
04/14/2021, 6:24 AMAndroid75
04/14/2021, 7:07 AMJoost Klitsie
04/14/2021, 8:32 AMMutableStatEFlow(ViewState(title = "", items = emptyList())
You can also wrap things in a sealed result object that can be Loading, Success, Error: Result<State>
Then you initialize your state with MutableStateFlow(Loading())
because that is often the state you are in at the beginning, loading your UI.
Also, for event you don't want to use a stateflow. An event is a 1-off thing you fire into the wild, doesn't need to have state (even if it can be replayed).Android75
04/15/2021, 3:11 AMIan Lake
04/15/2021, 3:12 AMStateFlow
Joost Klitsie
04/15/2021, 7:09 AM