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();
          }
    }
}
    
  1. 我将 AuthenticationBloc 订阅到我的 AuthenticateCredentialsUsecase 的状态流 class。
  2. 当在我的 LoginBloc 中调用 AuthenticateCredentialsUsecase 并验证凭据时...
  3. 然后我更新状态流 - _controller.add(AuthenticationStatus.authenticated);
  4. 哪个反过来会触发AuthenticationLogin事件 在 AuthenticationBloc
  5. 内部

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;
  }