preface
Probably haven’t posted in a long time… Sin sin, the Spring Festival is coming to an end, but also taking advantage of the current pneumonia special period, home nothing to write an article. That I’m still alive, and… Help me up. I can still learn.
The ViewModel, an important part of Jetpack, is already familiar.
And bringing it up today is to pay for my own stupidity… My previous self had assumed that the ViewModel would solve the problem of Activity destruction and reconstruction (but this was a mistake). Until stepped on the pit, just carefully think about…
The body of the
One, a brief introduction
ViewModel can’t handle destroy rebuild, which is obvious.
After all, the largest dimension that gets into a ViewModel instance is at the Activity level. Destroying and rebuilding means that the Activity instance has also changed, so it makes sense that the ViewModel that you get from this instance is also new…
In fact, we can also understand from official documents, such as this picture:
OnSaveInstanceState () is not included in the Scope of the ViewModel, so it is clear that the ViewModel will not actively handle destruction and rebuild.
Of course, there may be some friends who think this is just a guess… You can write your own demo and try it out, and you’ll see that all the variables in the ViewModel that you get after you destroy and rebuild are null.
Two, how to solve
2.1. Reference Documents
Of course, such an obvious problem, Google will certainly provide solutions. As a matter of fact, the following documents can help you find a quick solution (but you need to have your own science online), but you don’t want to read the official documents, so listen to me here…
Codelabs.developers.google.com/codelabs/an…
Developer.android.com/topic/libra…
2.2, actual combat
implementation "Androidx. Savedstate: savedstate: 1.0.0."
// KTX or Alpaha, please decide for yourself
implementation "Androidx. Savedstate: savedstate - KTX: 1.1.0 - alpha01"
Copy the code
2.2.1 New parameters of ViewModel
As we can see from the official documentation, the ViewModel needs a new parameter SavedStateHandle:
class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() { ... }
Copy the code
If you’re familiar with the ViewModel, you’ll realize that you need to provide a custom Fractory for the ViewModel.
However, Google is aware of this problem, and provides extension functions to quickly instantiate viewModels in activityViewModels() and Fragemtn-ktx: by activityViewModels(), by viewModels().
The above extension functions can help us deal with a single ViewModel constructor with additional SavedStateHandle.
2.2.2 How to use it
In fact, Google does not provide a particularly convenient solution for us, in order to be restored in the Activity level destroy rebuild, we need to modify the existing code.
In addition to the introduction of SavedStateHandle in the constructor, we need to modify the variable we need to restore, assuming we have a member variable called userName and a LiveData:
class DemoViewModel(private val state: SavedStateHandle) :ViewModel{
var userName: String? = ""
val userNameLiveData: LiveData = MutableLiveData<String>()
}
Copy the code
For userName, we need to modify SaveStateHandle as follows:
class DemoViewModel(private val state: SavedStateHandle) :ViewModel{
companion object{
const val SAVE_STATE_KEY_STRING = "saved_state_handle_user_name"
const val SAVE_STATE_KEY_LIVEDATE = "saved_state_handle_user_name_livedata"
}
var userName: String?
get() {
return state.get(SAVE_STATE_KEY_STRING)
}
set(value) {
state.set(SAVE_STATE_KEY_STRING, value)
}
fun getUserNameLiveData(a): LiveData<String> = state.getLiveData(SAVE_STATE_KEY_LIVEDATE)
fun saveNewName(newName: String) {
state.set(SAVE_STATE_KEY_LIVEDATE, newName); }}Copy the code
Then, the principle of
From the above example, we can see that Google just gave us the SavedStateHandle with the Save capability, so that we can get our own set variable at the time of destruction through the get method:
public <T> MutableLiveData<T> getLiveData(@NonNull String key) {
return getLiveDataInternal(key, false.null);
}
public <T> T get(@NonNull String key) {
return (T) mRegular.get(key);
}
Copy the code
OnSaveInstanceState () is the same as onSaveInstanceState().
// When triggering destruction, it goes to the Fragment method
void performSaveInstanceState(Bundle outState) {
// We usually use the method
onSaveInstanceState(outState);
// The implementation of this method is below
mSavedStateRegistryController.performSave(outState);
// Omit some code
}
void performSave(@NonNull Bundle outBundle) {
Bundle components = new Bundle();
if(mRestoredState ! =null) {
components.putAll(mRestoredState);
}
for (Iterator<Map.Entry<String, SavedStateProvider>> it =
mComponents.iteratorWithAdditions(); it.hasNext(); ) {
Map.Entry<String, SavedStateProvider> entry1 = it.next();
components.putBundle(entry1.getKey(), entry1.getValue().saveState());
}
outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
}
private final SavedStateProvider mSavedStateProvider = new SavedStateProvider() {
@Override
public Bundle saveState(a) {
Set<String> keySet = mRegular.keySet();
ArrayList keys = new ArrayList(keySet.size());
ArrayList value = new ArrayList(keys.size());
for (String key : keySet) {
keys.add(key);
value.add(mRegular.get(key));
}
Bundle res = new Bundle();
res.putParcelableArrayList("keys", keys);
res.putParcelableArrayList("values", value);
returnres; }};Copy the code
The above code doesn’t need any explanation, it’s too simple.
Fill a map, you can be interested in combining the source code to feel it, not very difficult:
The end of the
To be honest, dealing with the destruction and reconstruction of this common situation is not particularly important for business scenarios, so this part of the content can be said to be a matter of opinion, but based on this opportunity to look at the source seems to be excellent ~