Skip to content

GetX 路由原理


源码解读

GetMaterialApp

dart
class GetMaterialApp extends StatelessWidget {
  
  final GlobalKey<NavigatorState>? navigatorKey;

  // GetBuilder 为 StatefulWidget。方法执行顺序:initState -> init -> builder
  @override
  Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
    //创建 GetMaterialController
    init: Get.rootController,
    initState: (i) {
          //...
          //存储路由名称与路由映射关系
          if (getPages != null) {
            Get.addPages(getPages!);
          }
          //...
        },
    //执行默认 MaterialApp,并指定 navigatorKey
    // Get.key 会调用到 GetMaterialController.key 创建一个 GlobalKey<NavigatorState>
    builder: (_) => MaterialApp(
                navigatorKey: (navigatorKey == null ? Get.key : Get.addKey(navigatorKey!)),
                home: home,
                routes: routes ?? const <String, WidgetBuilder>{},
                initialRoute: initialRoute,
                onGenerateRoute: (getPages != null ? generator : onGenerateRoute),
                onGenerateInitialRoutes: (getPages == null || home != null) ? onGenerateInitialRoutes : initialRoutesGenerate,
                onUnknownRoute: onUnknownRoute,
                navigatorObservers: (navigatorObservers == null
                    ? <NavigatorObserver>[ GetObserver(routingCallback, Get.routing) ]
                    : <NavigatorObserver>[ GetObserver(routingCallback, Get.routing) ]..addAll(navigatorObservers!)),
                //...
              ),
  );

  Route<dynamic> generator(RouteSettings settings) {
    return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
  }
}

Get.toName()

dart
extension GetNavigation on GetInterface {
  
  Future<T?>? toNamed<T>(
    String page, {
    dynamic arguments,
    int? id,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
  }) {
    //...
    //global(id) 获取到 GlobalKey<NavigatorState>,即在 GetMaterialApp 中设置的 navigatorKey
    //  最后调用 NavigatorState.pushNamed() 走 Navigator路由逻辑
    return global(id).currentState?.pushNamed<T>( page, arguments: arguments);
  }
}
dart
// 根据 Navigator路由逻辑,pushNamed() 会调用 onGenerateRoute,即 GetMaterialApp.generator()
class GetMaterialApp extends StatelessWidget {
 
  @override
  Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
    //...
    builder: (_) => MaterialApp(
                home: home,
                initialRoute: initialRoute,
                onGenerateRoute: (getPages != null ? generator : onGenerateRoute),
                //...
              ),
  );

  Route<dynamic> generator(RouteSettings settings) {
    //内部通过路由name 获取 GetPage,返回 GetPageRoute 对象
    return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
  }
}
dart
class PageRedirect {
  
  GetPageRoute<T> page<T>() {
    //检查是否需要重定向
    while (needRecheck()) {}
    // isUnknown 默认为 false
    final r = (isUnknown ? unknownRoute : route)!;
    return GetPageRoute<T>(
      page: r.page,
      parameter: r.parameters,
      settings: isUnknown
          ? RouteSettings(
              name: r.name,
              arguments: settings!.arguments,
            )
          : settings,
      curve: r.curve,
      opaque: r.opaque,
      showCupertinoParallax: r.showCupertinoParallax,
      gestureWidth: r.gestureWidth,
      customTransition: r.customTransition,
      binding: r.binding,
      bindings: r.bindings,
      transitionDuration: r.transitionDuration ?? Get.defaultTransitionDuration,
      transition: r.transition,
      popGesture: r.popGesture,
      fullscreenDialog: r.fullscreenDialog,
      middlewares: r.middlewares,
    );
  }

  bool needRecheck() {
    //获取路由名称对应的路由数据。routeTree 是在 GetMaterialApp 中添加的(即 getPages)
    final match = Get.routeTree.matchRoute(settings!.name!);
    //走单个路由指定的中间件,返回 GetPage。
    final runner = MiddlewareRunner(match.route!.middlewares);
    route = runner.runOnPageCalled(match.route);
    //...
  }
}
dart
class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T>, PageRouteReportMixin {
  
  Widget _getChild() {
    //走单个路由指定中间件
    final middlewareRunner = MiddlewareRunner(middlewares);
    final localbindings = [
      if (bindings != null) ...bindings!,
      if (binding != null) ...[binding!]
    ];
    final bindingsToBind = middlewareRunner.runOnBindingsStart(localbindings);
    if (bindingsToBind != null) {
      for (final binding in bindingsToBind) {
        binding.dependencies();
      }
    }
    final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!;
    _child = middlewareRunner.runOnPageBuilt(pageToBuild());
    return _child!;
  }

  @override
  Widget buildContent(BuildContext context) {
    return _getChild();
  }
}

GetX 中间件

全局处理

设置方式

dart
GetMaterialApp(
  //...
  routingCallback: (routing) {
    if(routing.current == '/second'){
      openAds();
    }
  }
)

触发原理

设置监听

dart
class GetMaterialApp extends StatelessWidget {

  final ValueChanged<Routing?>? routingCallback;

  const GetMaterialApp({
    //...
    this.routingCallback,
    //...
  });

  @override
  Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
    //...
    builder: (_) => MaterialApp(
                //...
                //添加 navigatorObservers
                //  Get.routing 获取到 GetMaterialController 创建时内部创建的 Routing 对象
                navigatorObservers: (navigatorObservers == null
                    ? <NavigatorObserver>[ GetObserver(routingCallback, Get.routing) ]
                    : <NavigatorObserver>[ GetObserver(routingCallback, Get.routing) ]..addAll(navigatorObservers!)),
                //...
              ),
  );

  Route<dynamic> generator(RouteSettings settings) {
    return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
  }
}
dart
class GetObserver extends NavigatorObserver {
  
  @override
  void didPush(Route route, Route? previousRoute) {
    super.didPush(route, previousRoute);
    //调用 Routing.update(),更新路由信息
    _routeSend?.update((value) {
      //...
    });
    if (routing != null) {
      routing!(_routeSend);
    }
  }
}

触发分发

dart
class NavigatorState extends State<Navigator> with TickerProviderStateMixin, RestorationMixin {

  //刷新路由栈
  void _flushHistoryUpdates({bool rearrangeOverlay = true}) {
    //...
    
    _flushObserverNotifications();
    //...
  }

  //分发消息
  void _flushObserverNotifications() {
    if (_effectiveObservers.isEmpty) {
      _observedRouteDeletions.clear();
      _observedRouteAdditions.clear();
      return;
    }
    
    while (_observedRouteAdditions.isNotEmpty) {
      final _NavigatorObservation observation = _observedRouteAdditions.removeLast();
      _effectiveObservers.forEach(observation.notify);
    }

    while (_observedRouteDeletions.isNotEmpty) {
      final _NavigatorObservation observation = _observedRouteDeletions.removeFirst();
      _effectiveObservers.forEach(observation.notify);
    }
  }
}

单个路由处理

设置方式

dart
GetMaterialApp(
  initialRoute: '/',
  getPages: [
    GetPage(name: '/', page: () => MyHomePage()),
    GetPage(name: '/second', page: () => Second(),  middlewares: [LoginMiddleware()]),
  ],
)
  class LoginMiddleware extends GetMiddleware {}

触发原理

设置监听

dart
class GetPage<T> extends Page<T> {
  
  final List<GetMiddleware>? middlewares;
  
}

触发分发

dart
class PageRedirect {
  
  GetPageRoute<T> page<T>() {
    //检查是否需要重定向
    while (needRecheck()) {}
    //...
  }

  bool needRecheck() {
    //获取路由名称对应的路由数据。routeTree 是在 GetMaterialApp 中添加的(即 getPages)
    final match = Get.routeTree.matchRoute(settings!.name!);
    //走单个路由指定的中间件,返回 GetPage。
    final runner = MiddlewareRunner(match.route!.middlewares);
    route = runner.runOnPageCalled(match.route);
    //...
  }
}
dart
class MiddlewareRunner {
  MiddlewareRunner(this._middlewares);

  GetPage? runOnPageCalled(GetPage? page) {
    //根据优先级排序并遍历分发
    _getMiddlewares().forEach((element) {
      page = element.onPageCalled(page);
    });
    return page;
  }
}

读源码学到什么

GetX 路由是自己实现的吗?

不是,在 Navigator 路由基础上拓展出来的。

dart
extension GetNavigation on GetInterface {
  
  Future<T?>? toNamed<T>(
    String page, {
    dynamic arguments,
    int? id,
    bool preventDuplicates = true,
    Map<String, String>? parameters,
  }) {
    //...
    //global(id) 获取到 GlobalKey<NavigatorState>,即在 GetMaterialApp 中设置的 navigatorKey
    //  最后调用 NavigatorState.pushNamed() 走 Navigator路由逻辑
    return global(id).currentState?.pushNamed<T>( page, arguments: arguments);
  }
}

GetX 如何实现不需要 context 的

在 GetMaterialApp 内部给 MaterialApp 设置了 navigatorKey (GlobalKey<NavigatorState>),后续通过 GlobalKey 来获取并调用 NavigatorState 中的方法。

dart
//设置 GlobalKey<NavigatorState>
class GetMaterialApp extends StatelessWidget {
  
  final GlobalKey<NavigatorState>? navigatorKey;

  // GetBuilder 为 StatefulWidget。方法执行顺序:initState -> init -> builder
  @override
  Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
    //...
    //执行默认 MaterialApp,并指定 navigatorKey
    // Get.key 会调用到 GetMaterialController.key 创建一个 GlobalKey<NavigatorState>
    builder: (_) => MaterialApp(
                navigatorKey: (navigatorKey == null ? Get.key : Get.addKey(navigatorKey!)),
                //...
              ),
  );
}

//通过 GlobalKey 获取 NavigatorState
extension GetNavigation on GetInterface {
  
  Future<T?>? toNamed<T>(String page) {
    //...
    //global(id) 获取到 GlobalKey<NavigatorState>,即在 GetMaterialApp 中设置的 navigatorKey
    //  最后调用 NavigatorState.pushNamed() 走 Navigator路由逻辑
    return global(id).currentState?.pushNamed<T>( page, arguments: arguments);
  }
}

GetX 路由设置中,同时设置了全局和单个路由中间件执行顺序

单个路由比全局路由中间件优先级更高。

dart
class NavigatorState extends State<Navigator> with TickerProviderStateMixin, RestorationMixin {

  Future<T?> pushNamed<T extends Object?>(String routeName,) {
    //首先调用 _routeNamed() 获取路由名对应路由信息。其内部调用 onGenerateRoute() 此处为 PageRedirect.page()
    // PageRedirect.page() 内部逻辑会先执行单个路由中间件。
    //然后调用 push(),内部会执行到 _flushHistoryUpdates()
    return push<T?>(_routeNamed<T>(routeName, arguments: arguments)!);
  }
  
  //刷新路由栈
  void _flushHistoryUpdates({bool rearrangeOverlay = true}) {
    //...

    //触发执行全局路由中间件
    _flushObserverNotifications();
    //...
  }

Released under the MIT License.