jetpack library understands SavedStateHandle
Function
Cooperate with ViewModel to restore the related state data of ViewModel from the destruction and reconstruction of Activity. We know that when Activity is destroyed and rebuilt by the Android system, the onSaveInstanceState and onRestoreInstanceState methods will be called. This method is invisible to ViewModel. SavedStateHandle fills in Clear this gap so that ViewModel can save some state data through this
Description
SavedStateHandle is a key-value map used to retrieve and write data to the saved state through the set() and get() methods
How to use?
- Use SavedStateHandle as a construction parameter of ViewModel
- ViewModel internally generates a
LiveData
object through theSavedStateHandle.getLiveData
method. The data in LiveData is the data we want to persist. If the Activity is rebuilt, this LiveData will is the reconstructed data
Supported types
Theoretically, all types that can be saved by Bundle are supported.
Principle analysis
- SavedStateRegistryOwner
Used to indicate that this class has the ability to reconstruct data and is used to provide SavedStateRegistry
- SavedStateRegistryController
Control class of SavedStateRegistry
- SavedStateRegistry
Data storage and recovery
- SavedStateProvider
Encapsulate the data to be saved through Bundle
basic relationship
SavedStateRegistryOwner → SavedStateRegistryController → SavedStateRegistry → SavedStateProvider
SavedStateRegistryController can be understood as a wrapper class of SavedStateRegistry
Code flow analysis
save data
When Activity calls onSaveInstanceState, the performSave method of SavedStateRegistryController is called. The method is as follows
@MainThread fun performSave(outBundle: Bundle) {<!-- --> savedStateRegistry.performSave(outBundle) }
Directly calling the performSave method of SavedStateRegistry
@MainThread @Suppress("INACESSIBLE_TYPE") fun performSave(outBundle: Bundle) {<!-- --> val components = Bundle() // Create a Bundle //The state retained in the last rebuild is retained first if (restoredState != null) {<!-- --> components.putAll(restoredState) } val it: Iterator<Map.Entry<String, SavedStateProvider>> = this.components.iteratorWithAdditions() // As you can see, here we basically traverse the components, then call the saveState method and put it into the bundle we created. while (it.hasNext()) {<!-- --> val (key, value) = it.next() components.putBundle(key, value.saveState()) } //Finally save this part of the data to outBundle if (!components.isEmpty) {<!-- --> outBundle.putBundle(SAVED_COMPONENTS_KEY, components) } }
Reconstruct data
The reconstructed data is reconstructed in onCreate
@OptIn(markerClass = BuildCompat.PrereleaseSdkCheck.class) @Override protected void onCreate(@Nullable Bundle savedInstanceState) {<!-- --> // Restore the Saved State first so that it is available to //OnContextAvailableListener instances mSavedStateRegistryController.performRestore(savedInstanceState); mContextAwareHelper.dispatchOnContextAvailable(this); super.onCreate(savedInstanceState); ReportFragment.injectIfNeededIn(this); if (BuildCompat.isAtLeastT()) {<!-- --> mOnBackPressedDispatcher.setOnBackInvokedDispatcher( Api33Impl.getOnBackInvokedDispatcher(this) ); } if (mContentLayoutId != 0) {<!-- --> setContentView(mContentLayoutId); } }
Controller’s performRestore method is called
@MainThread fun performRestore(savedState: Bundle?) {<!-- --> // To support backward compatibility with libraries that do not explicitly // call performAttach(), we make sure that work is done here if (!attached) {<!-- --> performAttach() } val lifecycle = owner.lifecycle check(!lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {<!-- --> ("performRestore cannot be called when owner is ${lifecycle.currentState}") } savedStateRegistry.performRestore(savedState) }
Finally, the performRestore method of SavedStateRegistry is called
internal fun performRestore(savedState: Bundle?) {<!-- --> check(attached) {<!-- --> ("You must call performAttach() before calling " + "performRestore(Bundle).") } check(!isRestored) {<!-- --> "SavedStateRegistry was already restored." } restoredState = savedState?.getBundle(SAVED_COMPONENTS_KEY) isRestored = true }
Serialize previously saved values into restoredState
The SavedStateRegistry mechanism realizes the saving of data. To use this mechanism, you need to implement SavedStateProvider, and then register yourself in it through the registerSavedStateProvider of SavedRegistry.
So how is this mechanism used by ViewModel? Activity and Fragment implement the HasDefaultViewModelProviderFactory interface, such as Activity
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {<!-- --> if (mDefaultFactory == null) {<!-- --> mDefaultFactory = new SavedStateViewModelFactory( getApplication(), this, getIntent() != null ? getIntent().getExtras() : null); } return mDefaultFactory; }
When SavedStateViewModelFactory creates ViewModel, if there is SaveStateHandle in the constructor of ViewModel, pass
LegacySavedStateHandleController.create( savedStateRegistry!!, lifecycle, key, defaultArgs )
Create SavedStateHandleController and obtain SavedStateHandle.
fun create( registry: SavedStateRegistry, lifecycle: lifecycle, key: String?, defaultArgs: Bundle? ): SavedStateHandleController {<!-- --> // Get the bundle related to this ViewModel from the registry val restoredState = registry.consumeRestoredStateForKey(key!!) // This method is to split the key and value saved in restoreState and save them as a map val handle = createHandle(restoredState, defaultArgs) val controller = SavedStateHandleController(key, handle) controller.attachToLifecycle(registry, lifecycle) tryToAddRecreator(registry, lifecycle) return controller }
Finally, the ViewModel was created successfully. At this time, the SavedHandle also has saved data. After the SavedStateHandleController is created, it will register the created SavedStateProvider into the StateRegistry to realize the saving of data.
Finally
If you want to become an architect or want to break through the 20-30K salary range, then don’t be limited to coding and business, you must be able to select and expand, and improve your programming thinking. In addition, good career planning is also very important, and learning habits are important, but the most important thing is to be able to persevere. Any plan that cannot be implemented consistently is empty talk.
If you have no direction, here is a set of “Advanced Notes on the Eight Modules of Android” written by a senior architect at Alibaba to help you systematically organize messy, scattered, and fragmented knowledge, so that you can systematically and efficiently Master various knowledge points of Android development.
Compared with the fragmented content we usually read, the knowledge points in this note are more systematic, easier to understand and remember, and are strictly arranged according to the knowledge system.
Everyone is welcome to support with three clicks. If you need information in the article, just scan the CSDN official certification WeChat card at the end of the article to get it for free ↓↓↓ (There is also a small bonus of the ChatGPT robot at the end of the article, don’t miss it)