Reputation: 60161
As shown in https://stackoverflow.com/a/61166665/3286489, we could save LiveData in savedStateHandle.
I could do that easily https://stackoverflow.com/a/61166665/3286489
private val textLiveData: MutableLiveData<String>
init {
textLiveData = savedStateHandle.getLiveData(KEY)
}
However, when trying to save it as below,
savedStateHandle.set(KEY, textLiveData)
I got the error
java.lang.IllegalArgumentException: Can't put value with type class androidx.lifecycle.SavedStateHandle$SavingStateLiveData into saved state
Where did I get it wrong?
Upvotes: 8
Views: 11435
Reputation: 5683
That is because your you class is not acceptable.
You can put Parcelable
or Serializable
types.
Here is the list of ACCEPTABLE_CLASSES
private static final Class[] ACCEPTABLE_CLASSES = new Class[]{
//baseBundle
boolean.class,
boolean[].class,
double.class,
double[].class,
int.class,
int[].class,
long.class,
long[].class,
String.class,
String[].class,
//bundle
Binder.class,
Bundle.class,
byte.class,
byte[].class,
char.class,
char[].class,
CharSequence.class,
CharSequence[].class,
// type erasure ¯\_(ツ)_/¯, we won't eagerly check elements contents
ArrayList.class,
float.class,
float[].class,
Parcelable.class,
Parcelable[].class,
Serializable.class,
short.class,
short[].class,
SparseArray.class,
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? Size.class : int.class),
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? SizeF.class : int.class),
};
Upvotes: 11
Reputation: 81549
You can use val textLiveData: MutableLiveData<String> = savedStateHandle.getLiveData(KEY)
which constructs a MutableLiveData
that is automatically persisted to savedInstanceState
.
savedStateHandle.set(KEY, textLiveData)
You don't need to do this, because getLiveData
is a SavingStateLiveData
which automatically handles this.
Upvotes: 2
Reputation: 60161
Apparently the better answer is, we don't even need to
savedStateHandle.set(KEY, textLiveData.value)
While that is permissible, when we one do set
textLiveData.value = "Some data"
This already saved to the state. As textLiveData
is retrieved from savedStateHandle
as below.
textLiveData = savedStateHandle.getLiveData(KEY)
Hence the textLiveData
is already stored within the savedStateHandle
, and changes to textLiveData.value
is inadvertently get saved in savedStateHandle
.
Upvotes: 5
Reputation: 60161
After looking into the code, realize I just need to save the value, as what @Parth mentioned in the comment above.
savedStateHandle.set(KEY, textLiveData.value)
Explanation
If we look into the set
of SavedStateHandle.java
@MainThread
public <T> void set(@NonNull String key, @Nullable T value) {
validateValue(value);
@SuppressWarnings("unchecked")
MutableLiveData<T> mutableLiveData = (MutableLiveData<T>) mLiveDatas.get(key);
if (mutableLiveData != null) {
// it will set value;
mutableLiveData.setValue(value);
} else {
mRegular.put(key, value);
}
}
This shows that it will put the data into the mutableLiveData
that we store in mLiveDatas
if there is one.
To ensure that our liveData is in mLiveDatas
, we just need to use textLiveData = savedStateHandle.getLiveData(KEY)
at the start. Checkout the getLiveData
of
SavedStateHandle.java
@NonNull
private <T> MutableLiveData<T> getLiveDataInternal(
@NonNull String key,
boolean hasInitialValue,
@Nullable T initialValue) {
MutableLiveData<T> liveData = (MutableLiveData<T>) mLiveDatas.get(key);
if (liveData != null) {
return liveData;
}
SavingStateLiveData<T> mutableLd;
// double hashing but null is valid value
if (mRegular.containsKey(key)) {
mutableLd = new SavingStateLiveData<>(this, key, (T) mRegular.get(key));
} else if (hasInitialValue) {
mutableLd = new SavingStateLiveData<>(this, key, initialValue);
} else {
mutableLd = new SavingStateLiveData<>(this, key);
}
mLiveDatas.put(key, mutableLd);
return mutableLd;
}
It will create one and put into mLiveDatas
when we request for one, if there isn't one already.
Upvotes: -2