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

Flutter Bloc调用API时事件未注册处理程序错误排查

调用FetchUserDetails事件时提示未注册处理程序的问题排查与解决

错误日志

W/WindowOnBackDispatcher(10169): 应用未启用OnBackInvokedCallback。
W/WindowOnBackDispatcher(10169): 请在应用清单中设置'android:enableOnBackInvokedCallback="true"'。
E/flutter (10169): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] 未处理的异常:Bad state: add(FetchUserDetails) 被调用时未注册事件处理程序。
E/flutter (10169): 请确保通过on((event, emit) {...})注册处理程序
E/flutter (10169): #0      Bloc.add. (package:bloc/src/bloc.dart:91:9)
E/flutter (10169): #1      Bloc.add (package:bloc/src/bloc.dart:97:6)
E/flutter (10169): #2      _DashboardPageState._loadUsernameAndPin (package:mobile_banking/views/dashboard_page.dart:108:39)

相关代码实现

UserDetails 实体类

class UserDetails {
  final String username;
  final String password;
  final String deviceId; // Add required fields
  final String ipAddress;
  final String appVersion;
  final String platform;

  UserDetails({
    required this.username,
    required this.password,
    required this.deviceId,
    required this.ipAddress,
    required this.appVersion,
    required this.platform,
  });

  factory UserDetails.fromJson(Map<String, dynamic> json) {
    final data = json['data'];
    print(data);
    return UserDetails(
      username: json['username'] ?? '',
      password: json['password'] ?? '',
      deviceId: json['deviceId'] ?? '',
      ipAddress: json['ipAddress'] ?? '',
      appVersion: json['appVersion'] ?? '',
      platform: json['platform'] ?? '',
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'username': username,
      'password': password,
      'deviceId': deviceId,
      'ipAddress': ipAddress,
      'appVersion': appVersion,
      'platform': platform,
    };
  }

  @override
  String toString() {
    return 'UserDetails{username: $username, deviceId: $deviceId, ipAddress: $ipAddress, appVersion: $appVersion, platform: $platform}';
  }
}

UserDetailsRepository

class UserDetailsRepository {
  final String endpoint = 'url';

  late HttpService httpService;

  Future<UserDetails> getUserDetails(UserDetails userDetails) async {
    try {
      print('Requesting user details with: ${userDetails.toJson()}');
      final response = await httpService.request(
        method: HttpMethod.post,
        url: '$endpoint/api/iBank/UserAuth',
        body: userDetails.toJson(),
      );
      print("Response body: $response");
      print("Return response body: ${UserDetails.fromJson(response)}");
      return UserDetails.fromJson(response);
    } catch (e) {
      throw Exception('Failed to get user details');
    }
  }
}

状态类

abstract class UserDetailsState extends Equatable {
  @override
  List<Object?> get props => [];
}

class UserDetailsInitial extends UserDetailsState {}

class UserDetailsLoading extends UserDetailsState {}

class UserDetailsLoaded extends UserDetailsState {
  final Map<String, dynamic> userDetails;

  UserDetailsLoaded(this.userDetails);

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

class UserDetailsError extends UserDetailsState {
  final String message;

  UserDetailsError(this.message);

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

UserDetailsBloc(原错误实现)

class UserDetailsBloc extends Bloc<UserDetailsEvent, UserDetailsState> {
  UserDetailsBloc() : super(UserDetailsInitial());

  Stream<UserDetailsState> mapEventtoState(UserDetailsEvent event) async* {
    if (event is FetchUserDetails) {
      yield UserDetailsLoading();
      try {
        final fetchedDetails = await fetchUserDetailsFromStorage(event);
        print('user details fetched: $fetchedDetails');
        yield UserDetailsLoaded(fetchedDetails.toJson());
      } catch (e) {
        yield UserDetailsError('Failed to fetch user details: $e');
      }
    }
  }

  Future<UserDetails> fetchUserDetailsFromStorage(
      FetchUserDetails event) async {
    // Implement the logic to fetch user details from secure storage or an API
    // Return the fetched details
    const storage = FlutterSecureStorage();

    try {
      String? storedUsername = await storage.read(key: 'userName');
      String? storedPassword = await storage.read(key: 'pin');

      if (storedUsername != null && storedPassword != null) {
        // Create a UserDetails instance with the retrieved credentials
        UserDetails userDetails = UserDetails(
          username: storedUsername,
          password: storedPassword,
          deviceId: event.deviceId,
          ipAddress: event.ipAddress,
          appVersion: event.appVersion,
          platform: event.platform,
        );

        // Fetch the user details from the repository
        UserDetails fetchedUserDetails =
            await UserDetailsRepository().getUserDetails(userDetails);
        return fetchedUserDetails;
      } else {
        throw Exception('Stored credentials not found');
      }
    } catch (e) {
      throw Exception('Failed to fetch user details: $e');
    }
  }
}

问题原因

  1. 事件处理方法名拼写错误:原代码中mapEventtoState的驼峰写法错误,正确应为mapEventToState(第二个T大写),且未添加@override注解,导致Bloc无法识别该事件处理方法。
  2. Bloc版本API不兼容:如果使用的是新版本Bloc(v8+),官方已废弃mapEventToState,改用on<Event>的方式注册事件处理逻辑,原写法无法被新版本Bloc识别。

解决方案

方案1:修复mapEventToState写法(兼容旧版本Bloc)

修改UserDetailsBloc代码,修正方法名并添加@override:

class UserDetailsBloc extends Bloc<UserDetailsEvent, UserDetailsState> {
  UserDetailsBloc() : super(UserDetailsInitial());

  @override // 添加override注解
  Stream<UserDetailsState> mapEventToState(UserDetailsEvent event) async* { // 修正方法名
    if (event is FetchUserDetails) {
      yield UserDetailsLoading();
      try {
        final fetchedDetails = await fetchUserDetailsFromStorage(event);
        print('user details fetched: $fetchedDetails');
        yield UserDetailsLoaded(fetchedDetails.toJson());
      } catch (e) {
        yield UserDetailsError('Failed to fetch user details: $e');
      }
    }
  }

  // 其余代码保持不变...
}

方案2:迁移到新版本Bloc的on注册方式(推荐)

新版本Bloc推荐使用on<Event>来绑定事件与处理逻辑,修改后代码如下:

class UserDetailsBloc extends Bloc<UserDetailsEvent, UserDetailsState> {
  UserDetailsBloc() : super(UserDetailsInitial()) {
    // 注册FetchUserDetails事件的处理逻辑
    on<FetchUserDetails>((event, emit) async {
      emit(UserDetailsLoading());
      try {
        final fetchedDetails = await fetchUserDetailsFromStorage(event);
        print('user details fetched: $fetchedDetails');
        emit(UserDetailsLoaded(fetchedDetails.toJson()));
      } catch (e) {
        emit(UserDetailsError('Failed to fetch user details: $e'));
      }
    });
  }

  // 其余代码保持不变...
}

额外注意事项

  • 确保FetchUserDetails事件类已正确定义(需继承自UserDetailsEvent)。
  • UserDetailsRepository中的httpService未初始化,需在使用前完成初始化,否则会导致空指针异常。
  • 关于WindowOnBackDispatcher的警告,可在AndroidManifest.xml中添加android:enableOnBackInvokedCallback="true"到<application>标签中消除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:04:54