I am new to LiveData
thing in general and I am having a hard time understanding the difference between LiveData<String>()
and LiveData<String?>()
. I used them interchangeably and nothing seams to break. I know that LiveData.getValue()
is marked with @Nullable
in Java, so we end up getting String?
anyway. So what makes LiveData<String?>()
different from LiveData<String>()
?
CodePudding user response:
LiveData<String?>()
meens that livedata can store null, read please this article to be fully informed: https://kotlinlang.org/docs/null-safety.html
CodePudding user response:
This ended up a bit long but I hope it covers everything!
A LiveData
is meant to be observe
d. The observer receives data, and the LiveData
's type says what type that data is. A LiveData<String>
will only supply non-null String
s to its observers. A LiveData<String?>
can supply String
s and nulls.
Which of those you want depends on what you're doing! Do you need to supply nulls, e.g. for some kind of missing value or whatever? Should they be part of your data? If not, like in any other situation, avoid making the type nullable unless it needs to be.
When an observer first observe
s a LiveData
, it receives the current value. That way it can immediately handle the current data, update to display the current state, etc. But it's possible for a LiveData
to have no value initially:
// non-null
val liveDataWithValue = MutableLiveData<String>("hi")
val emptyLiveData = MutableLiveData<String>()
// nullable
val nullableLiveDataWithValue = MutableLiveData<String?>(null)
val emptyNullableLiveData = MutableLiveData<String?>()
The first one there has an initial value. If you observe it, and that value hasn't been updated, the observer will immediately be called with "hi"
for its parameter.
The second one has no value. If you observe that, the observer won't be called until a value is set on it. This is useful when you don't actually have any initial data - you can still set up your observer, and nothing will happen until some data is actually pushed.
The third one is the same as the first - it's a nullable String?
but with a value of null. That's still a value so if you observe
it, the observer will immediately be called with that null. It's still a piece of data your observer has to react to and process.
The last one is nullable but with no initial value. Like the second one, this means there's nothing for the observer to receive at first - but when it does have a value set on it, it could be a null. null is just another kind of value!
But if you go poking around at the LiveData
's value
property, instead of interacting with it through observe
, then that no value state is represented internally by null. Java (or at least the version Android targets) doesn't really have a representation of no value separate from null, so that's just how they have to do things. It just doesn't publish anything until you explicitly set a value on it.
So for each of these:
val emptyLiveData = MutableLiveData<String>()
val nullableLiveDataWithValue = MutableLiveData<String?>(null)
val emptyNullableLiveData = MutableLiveData<String?>()
if you read their value
in this state, it will be null for all of them. One explicitly has a value of null set on it, the others are both empty. This also means that even though emptyLiveData
's type is non-null, its value
property can be null, just because of this "can be empty" situation which is true for all LiveData
objects. The nullability of the type is purely about what gets passed to observers.
You generally shouldn't be reading value
anyway, except internally (wherever you're actually setting the value). Everything else should be interacting with that LiveData
by observing it and reacting to the values that are published, and those values will be whatever type (nullable or not) that you specified