BlocListener 混乱
BlocListener confusion
我正在尝试使用 flutter blocs 制作一个应用程序,但我遇到了 BlocListener 未被调用的问题,我无法弄清楚我做错了什么。
这是重现我的问题的最简代码:
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => AuthBloc(),
child: const AppView(),
);
}
}
/**************** APP VIEW **************/
class AppView extends StatefulWidget {
const AppView({Key? key}) : super(key: key);
@override
State<AppView> createState() => _AppViewState();
}
class _AppViewState extends State<AppView> {
final _navigatorKey = GlobalKey<NavigatorState>();
NavigatorState get _navigator => _navigatorKey.currentState!;
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: _navigatorKey,
builder: (context, child) {
print('App builder');
return BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
print('Bloc listener');
switch (state.status) {
case AuthStatus.authenticated:
_navigator.pushAndRemoveUntil<void>(
MaterialPageRoute(
builder: (context) {
return Center(
child: Column(
children: [
const Text('Home'),
ElevatedButton(
onPressed: () {
context.read<AuthBloc>().add(
const AuthStatusChanged(
AuthStatus.unauthenticated));
},
child: const Text('Log out'),
),
],
),
);
},
),
(route) => false,
);
break;
default:
_navigator.pushAndRemoveUntil<void>(
MaterialPageRoute(
builder: (context) {
return Center(
child: Column(
children: [
const Text('Login'),
ElevatedButton(
onPressed: () {
context.read<AuthBloc>().add(
const AuthStatusChanged(
AuthStatus.authenticated));
},
child: const Text('Log in'),
),
],
),
);
},
),
(route) => false,
);
break;
}
},
child: child,
);
},
onGenerateRoute: (_) => MaterialPageRoute(
builder: (context) {
return const Center(
child: Text('splash'),
);
},
),
);
}
}
/**************** AUTH BLOC CLASSES **************/
/**************** AUTH State **************/
enum AuthStatus { unknown, unauthenticated, authenticated }
class AuthState extends Equatable {
final AuthStatus status;
const AuthState._({
this.status = AuthStatus.unknown,
});
const AuthState.unknown() : this._();
const AuthState.authenticated() : this._(status: AuthStatus.authenticated);
const AuthState.unauthenticated()
: this._(status: AuthStatus.unauthenticated);
@override
List<Object?> get props => [status];
}
/**************** AUTH Event **************/
abstract class AuthEvent extends Equatable {
const AuthEvent();
@override
List<Object> get props => [];
}
class AuthStatusChanged extends AuthEvent {
final AuthStatus status;
const AuthStatusChanged(this.status);
@override
List<Object> get props => [status];
}
/**************** AUTH BLOC **************/
class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc() : super(const AuthState.unknown()) {
print('Bloc constructor');
on<AuthStatusChanged>(_onAuthStatusChanged);
}
_onAuthStatusChanged(
AuthStatusChanged event,
Emitter<AuthState> emit,
) async {
switch (event.status) {
case AuthStatus.unauthenticated:
return emit(const AuthState.unauthenticated());
case AuthStatus.authenticated:
return emit(const AuthState.authenticated());
default:
return emit(const AuthState.unknown());
}
}
}
当我启动应用程序时,我希望 BlocListener 被调用一次,但它却位于初始页面上。
我使用本教程生成了这段代码:https://bloclibrary.dev/#/flutterlogintutorial
编辑:
谢谢大家的洞察力,我不明白 BlocListener 不会在 initialState 上触发事件(我猜是 RTFM xD)。回顾我使用的教程,这是由“存储库”处理的,它提供创建时延迟的流,Bloc 正在侦听该流以触发状态事件的更改。重复使用相同的概念对我有用!
BlocListener 仅在状态改变时触发。在应用程序加载时,您可能想要触发一个 bloc 事件来更改 AuthBloc 状态。
这可以通过在 initState() 函数中添加一个 bloc 事件并放置一个断点以查看是否触发侦听器来实现。
https://pub.dev/documentation/flutter_bloc/latest/flutter_bloc/BlocListener-class.html
侦听器仅在状态更改后调用,在创建 AuthBloc
后不会调用。
还有一个提示:context.read<AuthBloc>().add(const AuthStatusChanged(AuthStatus.authenticated));
不要 那样做。更喜欢在你的 bloc 实例中创建将触发事件的方法,它使你的代码更容易测试,如果将 very_good_analysis
添加到你的项目中,这是一个由 VGV(flutter bloc 背后的同一家公司)构建的 linter,你将看到有一条 lint 规则反对它。
我正在尝试使用 flutter blocs 制作一个应用程序,但我遇到了 BlocListener 未被调用的问题,我无法弄清楚我做错了什么。
这是重现我的问题的最简代码:
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => AuthBloc(),
child: const AppView(),
);
}
}
/**************** APP VIEW **************/
class AppView extends StatefulWidget {
const AppView({Key? key}) : super(key: key);
@override
State<AppView> createState() => _AppViewState();
}
class _AppViewState extends State<AppView> {
final _navigatorKey = GlobalKey<NavigatorState>();
NavigatorState get _navigator => _navigatorKey.currentState!;
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: _navigatorKey,
builder: (context, child) {
print('App builder');
return BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
print('Bloc listener');
switch (state.status) {
case AuthStatus.authenticated:
_navigator.pushAndRemoveUntil<void>(
MaterialPageRoute(
builder: (context) {
return Center(
child: Column(
children: [
const Text('Home'),
ElevatedButton(
onPressed: () {
context.read<AuthBloc>().add(
const AuthStatusChanged(
AuthStatus.unauthenticated));
},
child: const Text('Log out'),
),
],
),
);
},
),
(route) => false,
);
break;
default:
_navigator.pushAndRemoveUntil<void>(
MaterialPageRoute(
builder: (context) {
return Center(
child: Column(
children: [
const Text('Login'),
ElevatedButton(
onPressed: () {
context.read<AuthBloc>().add(
const AuthStatusChanged(
AuthStatus.authenticated));
},
child: const Text('Log in'),
),
],
),
);
},
),
(route) => false,
);
break;
}
},
child: child,
);
},
onGenerateRoute: (_) => MaterialPageRoute(
builder: (context) {
return const Center(
child: Text('splash'),
);
},
),
);
}
}
/**************** AUTH BLOC CLASSES **************/
/**************** AUTH State **************/
enum AuthStatus { unknown, unauthenticated, authenticated }
class AuthState extends Equatable {
final AuthStatus status;
const AuthState._({
this.status = AuthStatus.unknown,
});
const AuthState.unknown() : this._();
const AuthState.authenticated() : this._(status: AuthStatus.authenticated);
const AuthState.unauthenticated()
: this._(status: AuthStatus.unauthenticated);
@override
List<Object?> get props => [status];
}
/**************** AUTH Event **************/
abstract class AuthEvent extends Equatable {
const AuthEvent();
@override
List<Object> get props => [];
}
class AuthStatusChanged extends AuthEvent {
final AuthStatus status;
const AuthStatusChanged(this.status);
@override
List<Object> get props => [status];
}
/**************** AUTH BLOC **************/
class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc() : super(const AuthState.unknown()) {
print('Bloc constructor');
on<AuthStatusChanged>(_onAuthStatusChanged);
}
_onAuthStatusChanged(
AuthStatusChanged event,
Emitter<AuthState> emit,
) async {
switch (event.status) {
case AuthStatus.unauthenticated:
return emit(const AuthState.unauthenticated());
case AuthStatus.authenticated:
return emit(const AuthState.authenticated());
default:
return emit(const AuthState.unknown());
}
}
}
当我启动应用程序时,我希望 BlocListener 被调用一次,但它却位于初始页面上。
我使用本教程生成了这段代码:https://bloclibrary.dev/#/flutterlogintutorial
编辑: 谢谢大家的洞察力,我不明白 BlocListener 不会在 initialState 上触发事件(我猜是 RTFM xD)。回顾我使用的教程,这是由“存储库”处理的,它提供创建时延迟的流,Bloc 正在侦听该流以触发状态事件的更改。重复使用相同的概念对我有用!
BlocListener 仅在状态改变时触发。在应用程序加载时,您可能想要触发一个 bloc 事件来更改 AuthBloc 状态。 这可以通过在 initState() 函数中添加一个 bloc 事件并放置一个断点以查看是否触发侦听器来实现。
https://pub.dev/documentation/flutter_bloc/latest/flutter_bloc/BlocListener-class.html
侦听器仅在状态更改后调用,在创建 AuthBloc
后不会调用。
还有一个提示:context.read<AuthBloc>().add(const AuthStatusChanged(AuthStatus.authenticated));
不要 那样做。更喜欢在你的 bloc 实例中创建将触发事件的方法,它使你的代码更容易测试,如果将 very_good_analysis
添加到你的项目中,这是一个由 VGV(flutter bloc 背后的同一家公司)构建的 linter,你将看到有一条 lint 规则反对它。