restoreState method Null safety

  1. @override
void restoreState(
  1. RestorationBucket? oldBucket,
  2. bool initialRestore
)
override

Called to initialize or restore the RestorablePropertys used by the State object.

This method is always invoked at least once right after State.initState to register the RestorablePropertys with the mixin even when state restoration is turned off or no restoration data is available for this State object.

Typically, registerForRestoration is called from this method to register all RestorablePropertys used by the State object with the mixin. The registration will either restore the property's value to the value described by the restoration data, if available, or, if no restoration data is available - initialize it to a property-specific default value.

The method is called again whenever new restoration data (in the form of a new bucket) has been provided to the mixin. When that happens, the State object must re-register all previously registered properties, which will restore their values to the value described by the new restoration data.

Since the method may change the value of the registered properties when new restoration state is provided, all initialization logic that depends on a specific value of a RestorableProperty should be included in this method. That way, that logic re-executes when the RestorablePropertys have their values restored from newly provided restoration data.

The first time the method is invoked, the provided oldBucket argument is always null. In subsequent calls triggered by new restoration data in the form of a new bucket, the argument given is the previous value of bucket.

Implementation

@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
  registerForRestoration(_rawNextPagelessRestorationScopeId, 'id');
  registerForRestoration(_serializableHistory, 'history');

  // Delete everything in the old history and clear the overlay.
  while (_history.isNotEmpty) {
    _history.removeLast().dispose();
  }
  assert(_history.isEmpty);
  _overlayKey = GlobalKey<OverlayState>();

  // Populate the new history from restoration data.
  _history.addAll(_serializableHistory.restoreEntriesForPage(null, this));
  for (final Page<dynamic> page in widget.pages) {
    final _RouteEntry entry = _RouteEntry(
      page.createRoute(context),
      initialState: _RouteLifecycle.add,
    );
    assert(
      entry.route.settings == page,
      'The settings getter of a page-based Route must return a Page object. '
      'Please set the settings to the Page in the Page.createRoute method.',
    );
    _history.add(entry);
    _history.addAll(_serializableHistory.restoreEntriesForPage(entry, this));
  }

  // If there was nothing to restore, we need to process the initial route.
  if (!_serializableHistory.hasData) {
    String? initialRoute = widget.initialRoute;
    if (widget.pages.isEmpty) {
      initialRoute = initialRoute ?? Navigator.defaultRouteName;
    }
    if (initialRoute != null) {
      _history.addAll(
        widget.onGenerateInitialRoutes(
          this,
          widget.initialRoute ?? Navigator.defaultRouteName,
        ).map((Route<dynamic> route) => _RouteEntry(
            route,
            initialState: _RouteLifecycle.add,
            restorationInformation: route.settings.name != null
              ? _RestorationInformation.named(
                name: route.settings.name!,
                arguments: null,
                restorationScopeId: _nextPagelessRestorationScopeId,
              )
              : null,
          ),
        ),
      );
    }
  }

  assert(
    _history.isNotEmpty,
    'All routes returned by onGenerateInitialRoutes are not restorable. '
    'Please make sure that all routes returned by onGenerateInitialRoutes '
    'have their RouteSettings defined with names that are defined in the '
    "app's routes table.",
  );
  assert(!_debugLocked);
  assert(() { _debugLocked = true; return true; }());
  _flushHistoryUpdates();
  assert(() { _debugLocked = false; return true; }());
}