Cubit 不听 Bloc

问题描述 投票:0回答:1

我正在开发一个 Flutter 应用程序,该应用程序遵循 BLoC 模式,具有干净的架构,并使用依赖注入进行服务管理。我有一个 处理用户身份验证并发出 来指示用户是否登录。我还有一个 应该监听 。当用户通过身份验证时, 应触发一个函数来获取用户信息。

问题描述

我面临的问题是 没有正确监听 。具体来说,构造函数内的侦听器似乎没有从接收流事件,导致在尝试访问用户数据时在主屏幕上显示空值。

用户Cubit

class UserCubit extends Cubit<UserState> {
  final AuthBloc _authBloc;
  final FetchUserinfoUsecase fetchUserinfoUsecase;
  late final StreamSubscription _authBlocSubscription;

  UserCubit(this._authBloc, this.fetchUserinfoUsecase)
      : super(const UserState.unknown()) {
    monitorAuthBloc();
  }

  void monitorAuthBloc() {
    _authBlocSubscription = _authBloc.stream.listen((authState) {
      log('AuthBloc state: $authState');

      if (authState.result == AuthResult.authenticated) {
        fetchUserInfo();
      }
    }, onDone: () {
      log('AuthBloc done');
    }, onError: (error) {
      log('AuthBloc error: $error');
    });
  }

  void fetchUserInfo() async {
    emit(state.copyWith(isLoading: true));
    final result = await fetchUserinfoUsecase();

    result.fold(
      (failure) => emit(state.copyWith(
        isLoading: false,
        updatedUser: null,
        updatedErrorMessage: failure.message,
      )),
      (instructor) => emit(
        state.copyWith(
          isLoading: false,
          updatedUser: instructor,
        ),
      ),
    );
  }

  @override
  Future<void> close() {
    _authBlocSubscription.cancel();
    return super.close();
  }
}

AuthBLoC

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  final InternetCubit internetCubit;
  late final StreamSubscription internetStreamSubscription;
  final LoginUsecase loginUsecase;
  final LogoutUsecase logoutUsecase;

  AuthBloc({
    required this.internetCubit,
    required this.loginUsecase,
    required this.logoutUsecase,
  }) : super(const AuthState.unknown()) {
    internetStreamSubscription = internetCubit.stream.listen((internetState) {
      log(internetState.toString());
    });
    on<LoginButtonPressed>(_onLoginButtonPressed);
    on<LogoutButtonPressed>(_onLogoutButtonPressed);
  }

  bool get isAlreadyLoggedIn => loginUsecase.isAlreadyLoggedIn;
  UserId? get userId => loginUsecase.userId;
  String? get email => loginUsecase.email;

  void _onLoginButtonPressed(
    LoginButtonPressed event,
    Emitter<AuthState> emit,
  ) async {
    emit(state.copyWith(isLoading: true));
    final result = await loginUsecase(
      LoginParams(
        email: event.email,
        password: event.password,
      ),
    );

    result.fold(
      (failure) => emit(state.copyWith(
        isLoading: false,
        updatedResult: AuthResult.unauthenticated,
        updatedErrorMessage: failure.errorMessage,
      )),
      (success) => emit(state.copyWith(
        isLoading: false,
        updatedResult: AuthResult.authenticated,
      )),
    );
  }

  void _onLogoutButtonPressed(
    LogoutButtonPressed event,
    Emitter<AuthState> emit,
  ) async {
    emit(state.copyWith(isLoading: true));
    final result = await logoutUsecase();
    result.fold(
      (failure) => emit(state.copyWith(
        isLoading: false,
        updatedErrorMessage: failure.errorMessage,
      )),
      (success) => emit(state.copyWith(
        isLoading: false,
        updatedResult: AuthResult.unauthenticated,
      )),
    );
  }

  @override
  Future<void> close() {
    internetStreamSubscription.cancel();
    return super.close();
  }
}

依赖注入设置

di.registerLazySingleton(() => InternetCubit(
      internetConnection: di.serviceLocator.call(),
    ))
  ..registerLazySingleton(() => AuthBloc(
      internetCubit: di.serviceLocator.call(),
      loginUsecase: di.serviceLocator.call(),
      logoutUsecase: di.serviceLocator.call(),
    ))
  ..registerFactory(() => UserCubit(
      di.serviceLocator.call(),
      di.serviceLocator.call(),
    ));

主要设置

MultiBlocProvider(
  providers: [
    BlocProvider(
      create: (_) => di.serviceLocator<InternetCubit>(),
      lazy: false,
    ),
    BlocProvider(
      create: (_) => di.serviceLocator<AuthBloc>(),
      lazy: false,
    ),
    BlocProvider(create: (_) => di.serviceLocator<UserCubit>()),
  ],
)

问题

UserCubit 似乎没有正确收听

AuthBloc
流。具体来说,[tag:UserCubit's] 构造函数内的侦听器似乎不响应来自 的流事件,导致当用户数据应该可用时,主屏幕上显示空值。

  • 查看流订阅: 我通过在 MonitorAuthBloc 方法中添加日志记录语句并确保正在调用侦听器来确认 UserCubit 正确订阅了 AuthBloc 流。
  • 已验证的国家排放量: 我通过在 _onLoginButtonPressed 和 _onLogoutButtonPressed 方法中添加日志记录语句来检查是否正在发出经过身份验证的状态,从而验证了 AuthBloc 是否正确发出状态。
  • 依赖注入配置: 我检查了依赖项注入设置,以确保正确创建和提供 AuthBloc 和 UserCubit。
  • 初始化顺序: 我检查了 MultiBlocProvider 中的初始化顺序,以确保 AuthBloc 和 UserCubit 按正确的顺序初始化。

我所期待的

我预计当 AuthBloc 发出经过身份验证的状态时,UserCubit 将收到此事件并触发 fetchUserInfo 方法。因此,应该获取用户数据并在主屏幕上正确显示。

问题

  1. UserCubit 监听 AuthBloc 直播的方式有问题吗?
  2. 问题是否与初始化顺序或状态发射时间有关?
  3. 如何确保 UserCubit 正确监听 AuthBloc 并响应更改?
flutter bloc cubit
1个回答
0
投票

看起来这是不同用户肘实例的问题。尝试将

UserCubit
初始化为单例而不是工厂。你真的需要这个吗:

  ..registerFactory(() => UserCubit(
        di.serviceLocator.call(),
        di.serviceLocator.call(),
      ));

而不是:

  ..registerSingleton(UserCubit(
        di.serviceLocator.call(),
        di.serviceLocator.call(),
      ))

另外,用

registerLazySingleton
实例化 cubit 然后在
lazy: false
中设置
BlocProvider
是不是某种聪明的技巧?

© www.soinside.com 2019 - 2024. All rights reserved.