Search code examples
flutterstatelistenerbloc

Flutter - MultiBlocProvider is in parent class and child class listner not listneing state


My parent class and multiprovider class

    return MultiBlocProvider(
  providers: [
    BlocProvider<WorkFlowCubit>(
        create: (_) => wf_sl.workflowSl<WorkFlowCubit>()),
    BlocProvider<LoginBloc>(
      create: (BuildContext context) => LoginBloc(ApiRepository()),
    ),
  ],
  child: BaseMyApp(currentThemeMode: (value) {
    currentTheme = value;
  }, child:
      BlocBuilder<AppCubit, AppCubitState>(builder: (context, snapshot) {
    //Base AppCubit for Theme
    return MaterialApp(
      title: AppStrings.kAppName,
      darkTheme: BaseTheme.buildDarkTheme(context),
      home: SplashScreen(),
      navigatorKey: AppNavigationRouter.instance.navigatorKey,
    );
  })),
);

Second class where i have listener not getting state updated

return Scaffold(
  body: BlocListener<LoginBloc, LoginState>(
    bloc: LoginBloc(ApiRepository()),
    listener: (context, state) {
     //not getting state here
    print("state*** $state");
   },
    child: Container(
        child: QpSkeletonLoginPage(
          btnTextStyle: AppTextStyles.btnStyle(
              context: context, color: ColorConstants.colorWhite),
          onLogin: () {
            BlocProvider.of<LoginBloc>(context).add(GetLoginUpdate("903XXX248","am@ravathi94"));
           // BaseRoutes.navigateToDashboard();
            _loginBloc.add(GetLoginUpdate("903XXX248","am@ravathi94"));
          },
          btnColor: ColorConstants.colorGreen,
        )),
  ),
);

Bloc where getting state updated

class LoginBloc extends Bloc<LoginEvent, LoginState> {
  ApiRepository _apiRepository = ApiRepository();
 
  LoginBloc(this._apiRepository) : super(UserLoadingState()) {
    on<GetLoginUpdate>((event, emit) async {
      emit(UserLoadingState());
      try {
        final keys = await _apiRepository.getAeskeyEncrypt(event.email, event.password);
        emit(UserAesKeyLoadedState(keys));
        final users = await _apiRepository.loginRepo(event.email, event.password);
        emit(UserLoginLoadedState(users));
      } catch (e) {
        emit(UserErrorState(e.toString()));
      }
    });
  }
}

Event class

abstract class LoginEvent extends Equatable {
  const LoginEvent();

  @override
  List<Object> get props => [];
}


class GetLoginUpdate extends LoginEvent {
 final String email;
 final String password;

 GetLoginUpdate(this.email,this.password);

  @override
  List<Object> get props => [email,password];

  @override
  String toString() => 'USER { email: $email }';
}

State class

@immutable
abstract class LoginState extends Equatable {}

//data loading state
class UserLoadingState extends LoginState {
  @override
  List<Object?> get props => [];
}

class UserLoginLoadedState extends LoginState {
  final LoginModel users;

  UserLoginLoadedState(this.users);

  @override
  List<Object?> get props => [users];
}

class UserAesKeyLoadedState extends LoginState {
  final AesEncryptModel users;

  UserAesKeyLoadedState(this.users);

  @override
  List<Object?> get props => [users];
}

class UserErrorState extends LoginState {
  final String error;

  UserErrorState(this.error);

  @override
  List<Object?> get props => [error];
}

Solution

  • Your listener is not being triggered because it is listening to a completely different instance of LoginBloc.

    In your MultiBlocProvider, you create one instance:

    BlocProvider<LoginBloc>(
      create: (BuildContext context) => LoginBloc(ApiRepository()),
    ),
    

    However, in your second class, you create a different LoginBloc instance.

    return Scaffold(
      body: BlocListener<LoginBloc, LoginState>(
        // Creates a new LoginBloc instance. Remove this line.
        // bloc: LoginBloc(ApiRepository()),
        listener: (context, state) {
          //not getting state here
          print("state*** $state");
        },
        child: Container(
          child: QpSkeletonLoginPage(
            btnTextStyle: AppTextStyles.btnStyle(
                context: context, color: ColorConstants.colorWhite),
            onLogin: () {
              /// Just access your [LoginBloc] through the context.
              final loginBloc = BlocProvider.of<LoginBloc>(context);
              loginBloc
                  .add(GetLoginUpdate("903XXX248", "am@ravathi94"));
              // BaseRoutes.navigateToDashboard();
            },
            btnColor: ColorConstants.colorGreen,
          ),
        ),
      ),
    );
    

    If you try now, the listener will trigger.

    Please read the Bloc documents. They're very clear: you do not need to specify a specific Bloc instance through the bloc argument unless explicitly managing multiple Blocs of the same type.