路由, 是前端页面永远绕不过去的一个坎。那么对于万物皆widget的Flutter,路由又会以怎么样的形式存在呢?🔎前端
咱们先从调用入口开始跟踪,git
Navigator.of(context).pushNamed("xxx")
github
那咱们就直接进入Navigator这个文件,文件的结构以下:数组
涉及到几个类,分别 RoutePopDisposition,Route,RouteSettings.NavigatorObserver,Navigator,NavigatorState
这几个类就是咱们了解路由的基础了,咱们先看到Navigator
, 好家伙,Navigator
果真又是一个Widget😏,接着利用Android Studio找出调用它的地方,以下:markdown
咱们先到app.dart一探究竟, 发现这里是对Navigator作了初始化工做 ,app
不过,仔细瞧瞧,发现这里又有一个上面提到的类—— NavigatorObserver
, 那先过去看看咯。less
/// An interface for observing the behavior of a [Navigator].
class NavigatorObserver {
/// The navigator that the observer is observing, if any.
NavigatorState get navigator => _navigator;
NavigatorState _navigator;
/// The [Navigator] pushed `route`.
///
/// The route immediately below that one, and thus the previously active
/// route, is `previousRoute`.
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { }
/// The [Navigator] popped `route`.
///
/// The route immediately below that one, and thus the newly active
/// route, is `previousRoute`.
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { }
/// The [Navigator] removed `route`.
///
/// If only one route is being removed, then the route immediately below
/// that one, if any, is `previousRoute`.
///
/// If multiple routes are being removed, then the route below the
/// bottommost route being removed, if any, is `previousRoute`, and this
/// method will be called once for each removed route, from the topmost route
/// to the bottommost route.
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) { }
/// The [Navigator] replaced `oldRoute` with `newRoute`.
void didReplace({ Route<dynamic> newRoute, Route<dynamic> oldRoute }) { }
/// The [Navigator]'s route `route` is being moved by a user gesture.
///
/// For example, this is called when an iOS back gesture starts.
///
/// Paired with a call to [didStopUserGesture] when the route is no longer
/// being manipulated via user gesture.
///
/// If present, the route immediately below `route` is `previousRoute`.
/// Though the gesture may not necessarily conclude at `previousRoute` if
/// the gesture is canceled. In that case, [didStopUserGesture] is still
/// called but a follow-up [didPop] is not.
void didStartUserGesture(Route<dynamic> route, Route<dynamic> previousRoute) { }
/// User gesture is no longer controlling the [Navigator].
///
/// Paired with an earlier call to [didStartUserGesture].
void didStopUserGesture() { }
}
复制代码
NavigatorObserver
是一个Navigator行为的观察者,能够监听到push
,remove
,pop
等行为,它能够在MaterialApp对属性navigatorObservers进行设置,以下:ide
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
navigatorObservers: [
MyObserver()
],
routes: {
"second": (context) => SecondPage(),
},
);
}
}
复制代码
接着咱们借助Android Studio查看Observer的调用, 如下是其中一个调用:post
咱们能够注意到,Navigator在push的时候调用了Observer的didPush, 第一个参数是即将push的route,第二个参数则是当前的路由页面,这样一来,咱们就能够经过全局的Observer监听到整个App的路由变化。
看到这里,我本身内心有两个疑惑🤔,第一个就是为何全局的Observer要设计为数组的形式,第二个就是咱们要怎么在当前页面监听本身的路由状态变化。学习
要解决这两个疑惑,须要从NavigatorObserver
入手,再次借助Android Studio(AS真是个好东西😅),不怎么费劲就找到一个继承自NavigatorObserver
的类RouteObserver
, 下面是它的描述:
A [Navigator] observer that notifies [RouteAware]s of changes to the state of their [Route].
此外还有一些相关的方法:
看到subscribe
, unsubscribe
了,实锤无疑了🤓,看来这个就是咱们在找的东西了,能够监听当前route的状态改变。 解决了第二个疑惑,其实也就顺带解决了第一个疑惑,既然有这种观察路由的须要,那么意味着须要多个观察者,那Observer设计为数组的形式也就很合理了。
下面是简单的用法:
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MainPage(),
navigatorObservers: [
routeObserver,
MyObserver()
],
routes: {
"设置": (context) => SettingsPage(),
},
);
}
}
复制代码
class _SettingsPageState extends State<SettingsPage> with RouteAware{
final settingsStore = SettingsStore();
@override
void didChangeDependencies() {
super.didChangeDependencies();
settingsStore.getPrefsData();
routeObserver.subscribe(this, ModalRoute.of(context));
}
@override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}
@override
void didPop() {
super.didPop();
}
@override
void didPush() {
super.didPush();
}
}
复制代码
用法也很简单,就是增长了一个全局的观察者,而后在使用的地方进行订阅和注销,这里又发现了一个新的类RouteAware
, 天啊😢,好多类,不过嘛,其实就是个简单的接口定义😎:
接着回过头去看到一开始的Navigator.of(context).pushNamed("xxx")
, 发现其实是调用了NavigatorState
的pushNamed
方法,而对于pushNamed
方法,又牵涉到name映射到route的关系,咱们来看看这一段的实现:
其实逻辑很简单,就是调用onGenerateRoute
生成route, 而且提供了兜底操做,容许使用onUnknownRoute
继续生成route。而上面这两个方法其实也是在MaterialApp
这个widget进行设置的,咱们照例进行了设置:
Route _onGenerateRoute(RouteSettings routeSettings) {
return null;
}
Route _onUnknownRoute(RouteSettings routeSettings) {
return MaterialPageRoute(settings:routeSettings, builder: (context) => UnKnowRoutePage());
}
复制代码
除了这两个属性以外,还提供了一个可供配置的routes
,提供name到route映射的map,以下:
{
routes: <String, WidgetBuilder>{"设置": (context) => SettingsPage()},
}
复制代码
紧接着,咱们找到看到WidgetsApp
这个widget,找到里面的_onGenerateRoute
方法,
到这里就豁然开朗了,优先取出routes
的路由,若是取不到,就调用onGenerateRoute
生成路由。
前篇差很少就到这里吧,中篇才是大头,各类Route
满天飞😪。
这个剖析前篇其实就是讲了Navigator
的初始化,还有NavigatorObserver
的应用,经过它能够监听本身路由的状态变化,而且研究了路由的生成配置原理以及兜底方案,固然讲的更多的还有Android Stduio的使用,经过AS在定位代码,查找代码引用确实有奇效。
Flutter笔记--Flutter页面嵌入Android Activity中
Flutter生命周期和Navigator、Route监听
点击flutter_demo,查看完整代码。