我正在开发一个 Flutter 应用程序,该应用程序遵循 BLoC 模式,具有干净的架构,并使用依赖注入进行服务管理。我有一个 authbloc 处理用户身份验证并发出 authresult 来指示用户是否登录。我还有一个 usercubit 应该监听 authbloc。当用户通过身份验证时,usercubit 应触发一个函数来获取用户信息。
我面临的问题是 usercubit 没有正确监听 authbloc。具体来说,usercubit构造函数内的侦听器似乎没有从authbloc接收流事件,导致在尝试访问用户数据时在主屏幕上显示空值。
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();
}
}
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] 构造函数内的侦听器似乎不响应来自 authbloc 的流事件,导致当用户数据应该可用时,主屏幕上显示空值。
我预计当 AuthBloc 发出经过身份验证的状态时,UserCubit 将收到此事件并触发 fetchUserInfo 方法。因此,应该获取用户数据并在主屏幕上正确显示。
看起来这是不同用户肘实例的问题。尝试将
UserCubit
初始化为单例而不是工厂。你真的需要这个吗:
..registerFactory(() => UserCubit(
di.serviceLocator.call(),
di.serviceLocator.call(),
));
而不是:
..registerSingleton(UserCubit(
di.serviceLocator.call(),
di.serviceLocator.call(),
))
?
另外,用
registerLazySingleton
实例化 cubit 然后在 lazy: false
中设置 BlocProvider
是不是某种聪明的技巧?