You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

flutter_bloc与HydratedBloc中BlocListener不监听状态变化排查

问题:BlocListener无法监听HydratedBloc的状态变化

我正在使用flutter_bloc库和HydratedBloc创建Auth bloc,目前遇到的问题是BlocListener无法监听状态变化,我猜测问题可能是fromJson函数返回的初始状态未触发新状态发射,以下是我的实现代码:

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
        providers: [
          BlocProvider(create: (context) => AuthBloc()),
        ],
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          theme: Themes.light,
          darkTheme: Themes.dark,
          themeMode: ThemeMode.dark,
          title: AppContants.appName,
          navigatorKey: NavigationService.navigatorKey,
          onGenerateRoute: Routes.navigateTo,
          builder: (BuildContext context, Widget? child) {
            child = EasyLoading.init()(context, child);

            return BlocListener<AuthBloc, AuthState>(
                listener: (context, AuthState state) {
                  //bloc listener is used to make a actions instead of builds
                  //bloc bulder is used to return a widget
                  print('state is $state');
                  if (state is AuthAuthenticatedState) {
                    // NavigationService.navigateAndRemoveUntil(Confirm.route);

                    NavigationService.navigateAndRemoveUntil(
                      Dashboard.route,
                    );
                  } else {
                    NavigationService.navigateAndRemoveUntil(Login.route);
                  }
                },
                child: child);
          },
        ));
  }
}


class AuthBloc extends HydratedBloc<AuthEvent, AuthState> {
  AuthBloc() : super(AuthInitial()) {
    on<AuthAuthenticatingEvent>(authAuthenticating);
    on<AuthUnAuthenticatingEvent>(authUnAuthenticating);
  }

  authAuthenticating(event, emit) async {
    await Future.delayed(const Duration(seconds: 1));
    emit(const AuthAuthenticatedState(''));
  }

  authUnAuthenticating(event, emit) {}

  @override
  AuthState? fromJson(Map<String, dynamic> json) {
    String? token = json['token'];
    if (token != null && token.isNotEmpty) {
      return AuthAuthenticatedState(token);
    }

    return AuthUnAuthenticatedState();
  }

  @override
  Map<String, dynamic>? toJson(AuthState state) {
    if (state is AuthAuthenticatedState) {
      return {'token': state.token};
    }
    return {};
  }
}

问题原因及解决方案

核心问题

HydratedBloc在初始化时,会通过fromJson加载持久化状态并直接替换初始状态,但这个过程不会触发emit操作,因此BlocListener无法监听到这个状态变化(BlocListener仅响应通过emit发射的状态)。

具体修复步骤

  1. 在AuthBloc中重写onHydrated方法,手动emit加载后的状态
    当HydratedBloc完成持久化状态加载后,onHydrated会被调用,此时手动emit当前状态即可触发BlocListener的监听逻辑:
class AuthBloc extends HydratedBloc<AuthEvent, AuthState> {
  AuthBloc() : super(AuthInitial()) {
    on<AuthAuthenticatingEvent>(authAuthenticating);
    on<AuthUnAuthenticatingEvent>(authUnAuthenticating);
  }

  // ... 原有方法保持不变

  @override
  void onHydrated() {
    // 手动emit加载后的状态,触发BlocListener
    emit(state);
    super.onHydrated();
  }
}
  1. 优化BlocListener的跳转逻辑,避免循环跳转
    当前代码每次状态变化都会强制跳转页面,可能导致重复跳转(比如已在Dashboard时再次收到AuthAuthenticatedState),建议添加路由判断:
BlocListener<AuthBloc, AuthState>(
  listener: (context, AuthState state) {
    print('state is $state');
    final currentRoute = NavigationService.navigatorKey.currentContext?.route.settings.name;
    
    if (state is AuthAuthenticatedState) {
      if (currentRoute != Dashboard.route) {
        NavigationService.navigateAndRemoveUntil(Dashboard.route);
      }
    } else {
      if (currentRoute != Login.route) {
        NavigationService.navigateAndRemoveUntil(Login.route);
      }
    }
  },
  child: child,
)
  1. 可选:调整初始状态与持久化状态的一致性
    由于fromJson返回的状态会覆盖构造函数中传入的AuthInitial,可以将构造函数的初始状态改为与fromJson的默认返回一致,避免状态混淆:
AuthBloc() : super(AuthUnAuthenticatedState()) {
  // ... 原有逻辑
}

内容的提问来源于stack exchange,提问作者guru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:47:13