在 Flutter 中使用服务定位器管理路由
问题
在 Flutter 中进行页面跳转需要访问到当前的 BuildContext
及目标页面的 Widget
,不利于代码的组织管理。
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
}
服务定位器(Service Locator)
The service locator pattern is a design pattern used in software development to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the “service locator”, which on request returns the information necessary to perform a certain task. Proponents of the pattern say the approach simplifies component-based applications where all dependencies are cleanly listed at the beginning of the whole application design, consequently making traditional dependency injection a more complex way of connecting objects. Critics of the pattern argue that it is an anti-pattern which obscures dependencies and makes software harder to test.
简单来说服务定位器模式可以将获得服务的过程封装在服务定位器中,应用程序的代码不需要管理维护服务的大量依赖,使应用程序的结构得到良好的分离。
应用
创建 NavigationService
首先创建 NavigationService
处理页面的跳转,它包含两个方法:navigateTo
、 goBack
分别负责页面的跳转和返回。
navigatorKey
是用来创建 Navigator
的 Key
,通过它可以直接得到 Navigator
而不需要使用 Navigator.of
从 BuildContext
中获取 Navigator
。
class NavigationService {
final GlobalKey<NavigatorState> navigatorKey =
new GlobalKey<NavigatorState>();
Future<dynamic> navigateTo(String routeName, {dynamic arguments}) {
return navigatorKey.currentState!
.pushNamed(routeName, arguments: arguments);
}
void goBack() {
navigatorKey.currentState!.pop();
}
}
注册 locator
在 get_it
的 setup 中注册 NavigationService
。
GetIt locator = GetIt.instance;
void setupLocator() {
locator.registerLazySingleton(() => NavigationService());
}
routes 生成
在 router.dart
中创建路由生成函数。页面参数的可以通过 RouteSettings
来传递。
const String HomePageRoute = '/';
const String LoginPageRoute = '/login';
const String WebViewPageRoute = '/web_view';
Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case HomePageRoute:
return MaterialPageRoute(builder: (context) => HomePage(title: 'Home'));
case LoginPageRoute:
return MaterialPageRoute(builder: (context) => LoginPage(title: 'Login'));
case WebViewPageRoute:
var args = settings.arguments! as Map<String, dynamic>;
var url = args['url'] as String;
var title = args['title'] as String;
return MaterialPageRoute(
builder: (context) => WebViewPage(
url: url,
title: title,
));
default:
return MaterialPageRoute(builder: (context) => HomePage(title: 'Home'));
}
}
在 MaterialApp 上定义路由
import 'package:flutter/material.dart';
import 'services/navigation_service.dart';
import 'router.dart' as router;
import 'get_it.dart';
void main() {
setupLocator();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: locator<NavigationService>().navigatorKey,
onGenerateRoute: router.generateRoute,
initialRoute: router.HomePageRoute
);
}
}
应用中调用
完成上述操作后,我们便可以在应用中的任意位置通过 locator
访问 NavigationService
来进行页面跳转:
class _HomePageState extends State<HomePage> {
final NavigationService _navigationService = locator<NavigationService>();
_onPressed () {
_navigationService.navigateTo(router.LoginPageRoute);
}
}
此时页面跳转仅需要访问到 locator
、NavigationService
和目标页路由的 name
。