Router<T> class
The dispatcher for opening and closing pages of an application.
This widget listens for routing information from the operating system (e.g.
an initial route provided on app startup, a new route obtained when an
intent is received, or a notification that the user hit the system back
button), parses route information into data of type T
, and then converts
that data into Page objects that it passes to a Navigator.
Additionally, every single part of that previous sentence can be overridden and configured as desired.
The routeInformationProvider can be overridden to change how the name of the route is obtained. the RouteInformationProvider.value when the Router is first created is used as the initial route, and subsequent notifications from the RouteInformationProvider to its listeners are treated as notifications that the route information has changed.
The backButtonDispatcher can be overridden to change how back button
notifications are received. This must be a BackButtonDispatcher, which is
an object where callbacks can be registered, and which can be chained
so that back button presses are delegated to subsidiary routers. The
callbacks are invoked to indicate that the user is trying to close the
current route (by pressing the system back button); the Router ensures
that when this callback is invoked, the message is passed to the
routerDelegate and its result is provided back to the
backButtonDispatcher. Some platforms don't have back buttons and on those
platforms it is completely normal that this notification is never sent. The
common backButtonDispatcher for root router is an instance of
RootBackButtonDispatcher, which uses a WidgetsBindingObserver to listen
to the popRoute
notifications from SystemChannels.navigation. A
common alternative is ChildBackButtonDispatcher, which must be provided
the BackButtonDispatcher of its ancestor Router (available via
Router.of).
The routeInformationParser can be overridden to change how names obtained
from the routeInformationProvider are interpreted. It must implement the
RouteInformationParser interface, specialized with the same type as the
Router itself. This type, T
, represents the data type that the
routeInformationParser will generate.
The routerDelegate can be overridden to change how the output of the
routeInformationParser is interpreted. It must implement the
RouterDelegate interface, also specialized with T
; it takes as input
the data (of type T
) from the routeInformationParser, and is responsible
for providing a navigating widget to insert into the widget tree. The
RouterDelegate interface is also Listenable; notifications are taken
to mean that the Router needs to rebuild.
Concerns regarding asynchrony
Some of the APIs (notably those involving RouteInformationParser and RouterDelegate) are asynchronous.
When developing objects implementing these APIs, if the work can be done entirely synchronously, then consider using SynchronousFuture for the future returned from the relevant methods. This will allow the Router to proceed in a completely synchronous way, which removes a number of complications.
Using asynchronous computation is entirely reasonable, however, and the API is designed to support it. For example, maybe a set of images need to be loaded before a route can be shown; waiting for those images to be loaded before RouterDelegate.setNewRoutePath returns is a reasonable approach to handle this case.
If an asynchronous operation is ongoing when a new one is to be started, the precise behavior will depend on the exact circumstances, as follows:
If the active operation is a routeInformationParser parsing a new route information: that operation's result, if it ever completes, will be discarded.
If the active operation is a routerDelegate handling a pop request: the previous pop is immediately completed with "false", claiming that the previous pop was not handled (this may cause the application to close).
If the active operation is a routerDelegate handling an initial route or a pushed route, the result depends on the new operation. If the new operation is a pop request, then the original operation's result, if it ever completes, will be discarded. If the new operation is a push request, however, the routeInformationParser will be requested to start the parsing, and only if that finishes before the original routerDelegate request completes will that original request's result be discarded.
If the identity of the Router widget's delegates change while an asynchronous operation is in progress, to keep matters simple, all active asynchronous operations will have their results discarded. It is generally considered unusual for these delegates to change during the lifetime of the Router.
If the Router itself is disposed while an an asynchronous operation is in progress, all active asynchronous operations will have their results discarded also.
No explicit signals are provided to the routeInformationParser or routerDelegate to indicate when any of the above happens, so it is strongly recommended that RouteInformationParser and RouterDelegate implementations not perform extensive computation.
Application architectural design
An application can have zero, one, or many Router widgets, depending on its needs.
An application might have no Router widgets if it has only one "screen", or if the facilities provided by Navigator are sufficient.
A particularly elaborate application might have multiple Router widgets, in a tree configuration, with the first handling the entire route parsing and making the result available for routers in the subtree. The routers in the subtree do not participate in route information parsing but merely take the result from the first router to build their sub routes.
Most applications only need a single Router.
URL updates for web applications
In the web platform, it is important to keeps the URL up to date with the app state. This ensures the browser constructs its history entry correctly so that its forward and backward buttons continue to work.
If the routeInformationProvider is a PlatformRouteInformationProvider and a app state change leads to Router rebuilds, the Router will detect such a event and retrieve the new route information from the RouterDelegate.currentConfiguration and the RouteInformationParser.restoreRouteInformation. If the location in the new route information is different from the current location, the router sends the new route information to the engine through the PlatformRouteInformationProvider.routerReportsNewRouteInformation.
By Providing implementations of these two methods in the subclasses and using the PlatformRouteInformationProvider, you can enable the Router widget to update the URL in the browser automatically.
You can force the Router to report the new route information back to the engine even if the RouteInformation.location has not changed. By calling the Router.navigate, the Router will be forced to report the route information back to the engine after running the callback. This is useful when you want to support the browser backward and forward buttons without changing the URL. For example, the scroll position of a scroll view may be saved in the RouteInformation.state. If you use the Router.navigate to update the scroll position, the browser will create a new history entry with the RouteInformation.state that stores the new scroll position. when the users click the backward button, the browser will go back to previous scroll position without changing the url bar.
You can also force the Router to ignore a one time route information update by providing a one time app state update in a callback and pass it into the Router.neglect. The Router will not report any route information even if it detects location change as a result of running the callback. This is particularly useful when you don't want the browser to create a browser history entry for this app state update.
You can also choose to opt out of URL updates entirely. Simply ignore the RouterDelegate.currentConfiguration and the RouteInformationParser.restoreRouteInformation without providing the implementations will prevent the Router from reporting the URL back to the web engine. This is not recommended in general, but You may decide to opt out in these cases:
-
If you are not writing a web application.
-
If you have multiple router widgets in your app, then only one router widget should update the URL (Usually the top-most one created by the WidgetsApp.router/MaterialApp.router/CupertinoApp.router).
-
If your app does not care about the in-app navigation using the browser's forward and backward buttons.
Otherwise, we strongly recommend implementing the RouterDelegate.currentConfiguration and the RouteInformationParser.restoreRouteInformation to provide optimal user experience in the web application.
- Inheritance
Constructors
-
Router({Key key,
RouteInformationProvider routeInformationProvider, RouteInformationParser< T> routeInformationParser,@required RouterDelegate< T> routerDelegate,BackButtonDispatcher backButtonDispatcher} ) -
Creates a router. [...]
const
Properties
- backButtonDispatcher → BackButtonDispatcher
-
The back button dispatcher for the router. [...]
final
- hashCode → int
-
The hash code for this object. [...]
@nonVirtual, read-only, inherited
- key → Key
-
Controls how one widget replaces another widget in the tree. [...]
final, inherited
-
routeInformationParser
→ RouteInformationParser<
T> -
The route information parser for the router. [...]
final
- routeInformationProvider → RouteInformationProvider
-
The route information provider for the router. [...]
final
-
routerDelegate
→ RouterDelegate<
T> -
The router delegate for the router. [...]
final
- runtimeType → Type
-
A representation of the runtime type of the object.
read-only, inherited
Methods
-
createElement(
) → StatefulElement -
Creates a StatefulElement to manage this widget's location in the tree. [...]
inherited
-
createState(
) → State< Router< T> > -
Creates the mutable state for this widget at a given location in the tree. [...]
override
-
debugDescribeChildren(
) → List< DiagnosticsNode> -
Returns a list of DiagnosticsNode objects describing this node's
children. [...]
@protected, inherited
-
debugFillProperties(
DiagnosticPropertiesBuilder properties ) → void -
Add additional properties associated with the node. [...]
inherited
-
noSuchMethod(
Invocation invocation ) → dynamic -
Invoked when a non-existent method or property is accessed. [...]
inherited
-
toDiagnosticsNode(
{String name, DiagnosticsTreeStyle style} ) → DiagnosticsNode -
Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep. [...]
inherited
-
toString(
{DiagnosticLevel minLevel: DiagnosticLevel.info} ) → String -
Returns a string representation of this object.
inherited
-
toStringDeep(
{String prefixLineOne: '', String prefixOtherLines, DiagnosticLevel minLevel: DiagnosticLevel.debug} ) → String -
Returns a string representation of this node and its descendants. [...]
inherited
-
toStringShallow(
{String joiner: ', ', DiagnosticLevel minLevel: DiagnosticLevel.debug} ) → String -
Returns a one-line detailed description of the object. [...]
inherited
-
toStringShort(
) → String -
A short, textual description of this widget.
inherited
Operators
-
operator ==(
Object other ) → bool -
The equality operator. [...]
@nonVirtual, inherited
Static Methods
-
Forces the Router to run the
callback
and reports the route information back to the engine. [...] -
neglect(
BuildContext context, VoidCallback callback ) → void -
Forces the Router to to run the
callback
without reporting the route information back to the engine. [...] -
of(
BuildContext context ) → Router - Retrieves the immediate Router ancestor from the given context. [...]