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

Flutter Bloc状态异常:FetchLoadingState无法转为FetchDataState

解决HydratedBloc状态类型不匹配异常

问题根源

你的FetchBloc类定义时,泛型状态指定为FetchDataState,但在_fetchWeather方法里emit了FetchLoadingState——这两个状态没有继承关系,属于不同类型,所以触发了type 'FetchLoadingState' is not a subtype of type 'FetchDataState'的类型转换异常。

解决步骤

  1. 定义统一的基础状态类
    让所有相关状态都继承同一个抽象类,这样Bloc的泛型就能兼容所有状态:
// 基础状态抽象类
abstract class FetchState {}

// 原有的数据状态,继承基础状态
class FetchDataState extends FetchState {
  FetchDataState({
    required this.fetchedData,
    required this.cityNames,
    this.snackBar = false,
    required this.date,
  });
  
  final List fetchedData;
  final List cityNames;
  final bool snackBar;
  final DateTime date;

  // HydratedBloc需要的序列化方法
  factory FetchDataState.fromJson(Map<String, dynamic> json) {
    return FetchDataState(
      fetchedData: json['fetchedData'] as List,
      cityNames: json['cityNames'] as List,
      snackBar: json['snackBar'] as bool,
      date: DateTime.parse(json['date'] as String),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'fetchedData': fetchedData,
      'cityNames': cityNames,
      'snackBar': snackBar,
      'date': date.toIso8601String(),
    };
  }
}

// 加载状态,同样继承基础状态
class FetchLoadingState extends FetchState {}
  1. 修改Bloc的泛型定义
    把Bloc的状态泛型从FetchDataState改成基础的FetchState,同时确保Emitter的类型也对应:
class FetchBloc extends HydratedBloc<FetchEvent, FetchState> {
  FetchBloc()
      : super(FetchDataState(fetchedData: const [], cityNames: const [], date: DateTime.now())) {
    on<FetchWeather>(_fetchWeather);
    on<FetchCurrentLocation>(_fetchCurrentLocationWeather);
    on<RefreshData>(_refreshData);
    on<DeleteData>(_deleteData);
  }

  // Emitter类型改为Emitter<FetchState>
  void _fetchWeather(FetchWeather event, Emitter<FetchState> emit) async {
    emit(FetchLoadingState());
    event = await getCurrentWeather(event.cityName);
    
    if (event.data!.city == "city not found") {
      // 访问state字段时,需要先转换为FetchDataState类型
      final currentDataState = state as FetchDataState;
      emit(
        FetchDataState(
          cityNames: List.from(currentDataState.cityNames),
          fetchedData: List.from(currentDataState.fetchedData),
          snackBar: true,
          date: DateTime.now(),
        ),
      );
    } else {
      // 处理正常获取数据的逻辑,emit更新后的FetchDataState
      final currentDataState = state as FetchDataState;
      emit(
        FetchDataState(
          cityNames: [...currentDataState.cityNames, event.data!.city],
          fetchedData: [...currentDataState.fetchedData, event.data!],
          snackBar: false,
          date: DateTime.now(),
        ),
      );
    }
  }

  // 处理HydratedBloc的序列化,只持久化FetchDataState
  @override
  FetchState? fromJson(Map<String, dynamic> json) {
    return FetchDataState.fromJson(json);
  }

  @override
  Map<String, dynamic>? toJson(FetchState state) {
    if (state is FetchDataState) {
      return state.toJson();
    }
    // 加载状态不需要持久化,返回null
    return null;
  }
}
  1. 额外注意事项
  • 当需要访问state中的具体字段(比如cityNames)时,必须先将state转换为FetchDataState类型,因为现在state的类型是抽象的FetchState。
  • HydratedBloc的序列化方法中,只对FetchDataState进行持久化,加载状态不需要保存,所以在toJson里做类型判断,非数据状态返回null。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 03:31:20