目录
1 方式一:使用全局GlobalKey
1.1 创建全局GlobalKey
配置路由 并设置 globalNavigatorKey
final GlobalKey<NavigatorState> globalNavigatorKey = GlobalKey();
class MyApp extends StatelessWidget {
const MyApp({
Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// 配置路由 并设置 globalNavigatorKey
return MaterialApp(
initialRoute: "/",
navigatorKey: globalNavigatorKey,
onGenerateRoute: (settings) {
final routeName = settings.name;
switch (routeName) {
case "/":
return ...
case "/login":
return MaterialPageRoute(
builder: (context) => const LoginPage(),
);
case "/tabPage":
return MaterialPageRoute(builder: (context) => const TabPage());
default:
return ...;
}
},
);
}
}
1.2 网络请求拦截器中检测到Token过期则跳转页面
此处使用网络请求框架是 dio
,添加拦截器,并使用 globalNavigatorKey 跳转登录页面。
// 添加拦截器
final dio = Dio()..interceptors.add(ApiInterceptor());
class ApiInterceptor extends InterceptorsWrapper {
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
super.onError(err, handler);
int? statusCode = err.response?.statusCode;
if (statusCode == 401) {
// 跳转登录页面并清空栈
globalNavigatorKey.currentState
?.pushNamedAndRemoveUntil('/login', (route) => false);
}
}
}
1.3 可能出现的问题
当同时存在多个网络请求时,拦截器中跳转登录页面的操作可能会同时调用几次,出现多次跳转登录页面的情况。
2 方式二:使用事件总线
2.1 创建事件总线
class EventBus {
//私有构造函数
EventBus._internal();
static EventBus? _instance;
static EventBus get instance => _getInstance();
static EventBus _getInstance() {
return _instance ??= EventBus._internal();
}
// 存储事件回调方法
final Map<String, Function> _events = {
};
// 设置事件监听
void addListener(String eventKey, Function callback) {
_events[eventKey] = callback;
}
// 移除监听
void removeListener(String eventKey) {
_events.remove(eventKey);
}
// 提交事件
void commit(String eventKey) {
_events[eventKey]?.call();
}
}
class EventKeys {
static const String logout = "Logout";
}
2.2 监听登出事件
登录成功后,在主页面设置登出事件监听,事件响应后立即移除监听。
class TabPage extends StatefulWidget {
const TabPage({
Key? key}) : super(key: key);
@override
State<TabPage> createState() => _TabPageState();
}
class _TabPageState extends State<TabPage> {
@override
void initState() {
super.initState();
EventBus.instance.addListener(EventKeys.logout, () {
// 移除事件监听
EventBus.instance.removeListener(EventKeys.logout);
// 跳转登录页面
Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false);
});
}
@override
void dispose() {
// 移除事件监听
EventBus.instance.removeListener(EventKeys.logout);
super.dispose();
}
@override
Widget build(BuildContext context) {
return ...
}
}
2.3 网络请求拦截器中触发登出事件
final dio = Dio()..interceptors.add(ApiInterceptor());
class ApiInterceptor extends InterceptorsWrapper {
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
super.onError(err, handler);
int? statusCode = err.response?.statusCode;
if (statusCode == 401) {
// 触发登出事件
EventBus.instance.commit(EventKeys.logout);
}
}
}