How do you usually handle initial null values for states? In the old way, I have a `Flow<T>` t...
k
How do you usually handle initial null values for states? In the old way, I have a
Flow<T>
then I just observe it and wait for the initial value before I update the UI. Now, I’m trying to consume it and it always needs an initial value. I tried to do
.collectAsState(initial = null)
but then it makes it nullable and I have to perform null checking on every flow. Is there a better practice around this? I’d like to have
Flow<T>
rather than
Flow<T?>
. Thanks in advance!
d
Well, the first emission might take some time, what do you want the value to be before then?
You also have the option of using
stateIn
in a view model or something, to wait for the first value.
m
If you have a few separate states of the view like e.g. in an LCE pattern and then you expose them via StateFlow then you don't need to care about any initial value. Every screen usually has some Loading state (be it a progress indicator or just an unpopulated view).
k
Yeah null makes sense since technically, there’s no data yet. Kinda just removes the null-safety. I have lots of flows that are privately null but exposed as non-null and for one flow, it’s ok but with a lot of fields, that’s a lot of null checks. The problem in using
stateIn
is that it’s a suspend function. 😕 so I can’t do a
Copy code
private val _myFlow = MutableStateFlow<T?>(null)
val myFlow get() = _myFlow.filterNotNull().stateIn(scope)
I guess doing a redesign and using sealed classes would do the trick and make it better
z
Making a thing nullable in kotlin does not remove null-safety, since the compiler will still complain if you forget to check for null.
5
m
But you can just expose the StateFlow which has collectAsState() with no additional initial param. If you use MutableStateFlow in your viewmodel, that should be enough
k
Oops yeah, not null-safety but just the added effort of handling nullables.
e
You can also make a wrapper around your state:
Copy code
sealed interface StateWrapper {
  object Initial : StateWrapper
  data class State(val actualState: State) : StateWrapper
}
Then you can do
collectAsState(initial = StateWrapper.Initial
and react to that by not rendering, showing skeletons, etc...
k
Yup, that’s the route I was intending to take when I said it redesign it via sealed classes earlier. Thanks for adding code as a sample.
e
Oops, scanned quickly and didn't see that message 😅
u
Whats the issue? If state == null then empty UI or progressbar or something like that; else filled ui, and there youll be smartcasted to non null
👆 1
d
Smart cast didn't work on delegates sadly.
k
The issue is if you have a lot of states so that means
if (state1 != null && state2 != null … && stateN != null)
and I’m trying to avoid that. And yes, smart cast doesn’t work on delegates so I had to force the null