Dart:如何在另一个 bloc 中正确发送 bloc 事件
Dart: How to properly dispatch bloc event in another bloc
我需要在我的 LoginBloc 中访问 AuthenticationBloc,这样我就可以在登录成功时触发 AuthenticationLogin() 事件。到目前为止我所做的没有奏效。
我做了什么:
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final AuthenticationBloc authenticationBloc;
final AuthenticateCredentialsUsecase authenticateCredentialsUsecase;
//code
Stream<LoginState> mapEventToState(
LoginEvent event,
) async* {
//code
authenticationBloc.add(AuthenticationLogin());
yield LoginLoadSuccess();
//code
}
}
我想要完成的事情:
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) {
return BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
if (state is AuthenticationAuthenticated) {
_navigator.pushAndRemoveUntil<void>(
HomePage.route(),
(route) => false,
);
}
else if (state is AuthenticationUnauthenticated){
_navigator.pushAndRemoveUntil<void>(
LoginScreen.route(),
(route) => false,
);
}
},
child: child,
);
},
onGenerateRoute: (_) => SplashPage.route(),
);
}
}
如您所见,用户当前位于 LoginScreen 中,一旦登录成功,我需要在 AuthenticationBloc() 中生成 AuthenticationAuthenticated() 状态,以便将我的用户定向到 HomePage()
如何在我的 LoginBloc() 中生成 AuthenticationBloc() 的 AuthenticationAuthenticated() 状态 - 因为我的登录逻辑发生在 LoginBloc 中。
这是一种方法。您必须调用 BlocBuilder 来处理构建小部件以响应新状态。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
debugShowCheckedModeBanner: false,
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
//If the login is successful, show homepage
if (state is AuthenticationAuthenticated) {
return HomePage();
}
//If the login failed, show login screen
if (state is AuthenticationUnauthenticated) {
return LoginScreen();
}
//If the login is in process, show loading indicator
if (state is AuthenticationInProgress) {
return LoadingIndicator();
}
return SplashScreen();
},
),
);
}
}
一开始状态是AuthenticationUnauthenticated,显示登录界面。如果登录成功则显示主页,否则如果登录失败则显示登录屏幕。
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final AuthenticationBloc authenticationBloc;
final AuthenticateCredentialsUsecase authenticateCredentialsUsecase;
//code
Stream<LoginState> mapEventToState(
LoginEvent event,
) async* {
if(event is LoginButtonPressed) {
// some logic code
// eg. : final response = UserRepository.login(username: event.username, password: event.password);
authenticationBloc.add(AuthenticationLogin());
//code
}
}
}
这是将处理身份验证的 AuthenticationBloc () 代码。
class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState>{
//code
Stream<AuthenticationState> mapEventToState(
AuthenticationEvent event,
) async* {
if(event is AuthenticationLogin) {
yield AuthenticationInProgress();
//code
yield AuthenticationAuthenticated();
}
}
}
- 我将 AuthenticationBloc 订阅到我的 AuthenticateCredentialsUsecase 的状态流 class。
- 当在我的 LoginBloc 中调用 AuthenticateCredentialsUsecase 并验证凭据时...
- 然后我更新状态流 -
_controller.add(AuthenticationStatus.authenticated);
- 哪个反过来会触发AuthenticationLogin事件
在 AuthenticationBloc
内部
AuthenticationBloc
AuthenticationBloc({
@required CheckAuthenticationStatusUsecase checkAuthenticationStatus,
@required LogoutAuthenticatedUserUsecase logoutAuthenticatedUser,
@required AuthenticateCredentialsUsecase authenticateCredentials,
}) : assert(checkAuthenticationStatus != null),
assert(logoutAuthenticatedUser != null),
assert(authenticateCredentials != null),
checkAuthenticationStatusUsecase = checkAuthenticationStatus,
logoutAuthenticatedUserUsecase = logoutAuthenticatedUser,
authenticateCredentialsUsecase = authenticateCredentials,
super(AuthenticationInitial()) {
add(AuthenticationStatusRequested());
_loginStatusSubscription =
authenticateCredentialsUsecase.status.listen((event) {
if (event == AuthenticationStatus.authenticated) {
add(AuthenticationLogin());
}
});
}
AuthenticateCredentialsUsecase
final _controller = StreamController<AuthenticationStatus>();
Stream<AuthenticationStatus> get status async* {
yield AuthenticationStatus.unknown;
yield* _controller.stream;
}
void dispose() => _controller.close();
@override
Future<Either<Failure, AuthenticatedUser>> call(AuthenticationParams params) async {
final result = await repository.authenticateCredentials(params.userName, params.password);
if(result is Right){
_controller.add(AuthenticationStatus.authenticated);
}
return result;
}
我需要在我的 LoginBloc 中访问 AuthenticationBloc,这样我就可以在登录成功时触发 AuthenticationLogin() 事件。到目前为止我所做的没有奏效。
我做了什么:
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final AuthenticationBloc authenticationBloc;
final AuthenticateCredentialsUsecase authenticateCredentialsUsecase;
//code
Stream<LoginState> mapEventToState(
LoginEvent event,
) async* {
//code
authenticationBloc.add(AuthenticationLogin());
yield LoginLoadSuccess();
//code
}
}
我想要完成的事情:
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) {
return BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
if (state is AuthenticationAuthenticated) {
_navigator.pushAndRemoveUntil<void>(
HomePage.route(),
(route) => false,
);
}
else if (state is AuthenticationUnauthenticated){
_navigator.pushAndRemoveUntil<void>(
LoginScreen.route(),
(route) => false,
);
}
},
child: child,
);
},
onGenerateRoute: (_) => SplashPage.route(),
);
}
}
如您所见,用户当前位于 LoginScreen 中,一旦登录成功,我需要在 AuthenticationBloc() 中生成 AuthenticationAuthenticated() 状态,以便将我的用户定向到 HomePage()
如何在我的 LoginBloc() 中生成 AuthenticationBloc() 的 AuthenticationAuthenticated() 状态 - 因为我的登录逻辑发生在 LoginBloc 中。
这是一种方法。您必须调用 BlocBuilder 来处理构建小部件以响应新状态。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
debugShowCheckedModeBanner: false,
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
//If the login is successful, show homepage
if (state is AuthenticationAuthenticated) {
return HomePage();
}
//If the login failed, show login screen
if (state is AuthenticationUnauthenticated) {
return LoginScreen();
}
//If the login is in process, show loading indicator
if (state is AuthenticationInProgress) {
return LoadingIndicator();
}
return SplashScreen();
},
),
);
}
}
一开始状态是AuthenticationUnauthenticated,显示登录界面。如果登录成功则显示主页,否则如果登录失败则显示登录屏幕。
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final AuthenticationBloc authenticationBloc;
final AuthenticateCredentialsUsecase authenticateCredentialsUsecase;
//code
Stream<LoginState> mapEventToState(
LoginEvent event,
) async* {
if(event is LoginButtonPressed) {
// some logic code
// eg. : final response = UserRepository.login(username: event.username, password: event.password);
authenticationBloc.add(AuthenticationLogin());
//code
}
}
}
这是将处理身份验证的 AuthenticationBloc () 代码。
class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState>{
//code
Stream<AuthenticationState> mapEventToState(
AuthenticationEvent event,
) async* {
if(event is AuthenticationLogin) {
yield AuthenticationInProgress();
//code
yield AuthenticationAuthenticated();
}
}
}
- 我将 AuthenticationBloc 订阅到我的 AuthenticateCredentialsUsecase 的状态流 class。
- 当在我的 LoginBloc 中调用 AuthenticateCredentialsUsecase 并验证凭据时...
- 然后我更新状态流 -
_controller.add(AuthenticationStatus.authenticated);
- 哪个反过来会触发AuthenticationLogin事件 在 AuthenticationBloc 内部
AuthenticationBloc
AuthenticationBloc({
@required CheckAuthenticationStatusUsecase checkAuthenticationStatus,
@required LogoutAuthenticatedUserUsecase logoutAuthenticatedUser,
@required AuthenticateCredentialsUsecase authenticateCredentials,
}) : assert(checkAuthenticationStatus != null),
assert(logoutAuthenticatedUser != null),
assert(authenticateCredentials != null),
checkAuthenticationStatusUsecase = checkAuthenticationStatus,
logoutAuthenticatedUserUsecase = logoutAuthenticatedUser,
authenticateCredentialsUsecase = authenticateCredentials,
super(AuthenticationInitial()) {
add(AuthenticationStatusRequested());
_loginStatusSubscription =
authenticateCredentialsUsecase.status.listen((event) {
if (event == AuthenticationStatus.authenticated) {
add(AuthenticationLogin());
}
});
}
AuthenticateCredentialsUsecase
final _controller = StreamController<AuthenticationStatus>();
Stream<AuthenticationStatus> get status async* {
yield AuthenticationStatus.unknown;
yield* _controller.stream;
}
void dispose() => _controller.close();
@override
Future<Either<Failure, AuthenticatedUser>> call(AuthenticationParams params) async {
final result = await repository.authenticateCredentials(params.userName, params.password);
if(result is Right){
_controller.add(AuthenticationStatus.authenticated);
}
return result;
}