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

使用SharedPreferences实现Flutter地铁站点收藏持久化遇错求助

问题分析与解决方案

核心问题拆解

  • 枚举类型无法直接JSON序列化:BranchType是枚举,默认jsonEncode无法处理枚举值,会触发序列化错误。
  • 自定义类TransitData缺少JSON转换逻辑:如果TransitData是自定义类,未实现toJson/fromJson方法会导致序列化失败。
  • SharedPref方法逻辑错误:返回类型与实际数据结构不匹配,且空值处理不当会引发JSON解析异常。
  • 异步调用时机错误:在setState中直接调用异步存储方法,未等待写入完成就读取,可能导致数据不一致。

逐步修复代码

1. 修复枚举的JSON序列化

给BranchType扩展序列化/反序列化方法:

enum BranchType { red, blue, green }

extension BranchTypeExtension on BranchType {
  String toJson() => name; // 用枚举名称作为序列化值
  static BranchType fromJson(String json) => BranchType.values.firstWhere((e) => e.name == json);
}

2. 完善MetroStation的JSON转换逻辑

更新fromJson和toJson,适配枚举和TransitData:

class MetroStation {
  final String ukrName;
  final String engName;
  final double depth;
  final String iconImage;
  final TransitData? transitData;
  final BranchType branchType;
  bool isFavourite;

  MetroStation({
    required this.isFavourite,
    required this.branchType,
    this.transitData,
    required this.depth,
    required this.iconImage,
    required this.ukrName,
    required this.engName,
  });

  factory MetroStation.fromJson(Map<String, dynamic> json) => MetroStation(
        ukrName: json['ukrName'],
        engName: json['engName'],
        depth: json['depth'],
        iconImage: json['iconImage'],
        branchType: BranchTypeExtension.fromJson(json['branchType']),
        isFavourite: json['isFavourite'],
        transitData: json['transitData'] != null ? TransitData.fromJson(json['transitData']) : null,
      );

  Map<String, dynamic> toJson() => {
        'ukrName': ukrName,
        'engName': engName,
        'depth': depth,
        'iconImage': iconImage,
        'branchType': branchType.toJson(),
        'isFavourite': isFavourite,
        'transitData': transitData?.toJson(),
      };

  // 重写==和hashCode,确保remove方法能正确匹配元素
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is MetroStation &&
          runtimeType == other.runtimeType &&
          ukrName == other.ukrName &&
          engName == other.engName;

  @override
  int get hashCode => ukrName.hashCode ^ engName.hashCode;
}

3. 实现TransitData的JSON转换

假设TransitData结构如下,补充转换方法:

class TransitData {
  final String someField;

  TransitData({required this.someField});

  factory TransitData.fromJson(Map<String, dynamic> json) => TransitData(
        someField: json['someField'],
      );

  Map<String, dynamic> toJson() => {
        'someField': someField,
      };
}

4. 重构SharedPref类

适配列表类型,修复空值处理:

const favouriteKey = 'favourite_stations';

class SharedPref {
  static Future<void> saveFavourites(List<MetroStation> stations) async {
    final prefs = await SharedPreferences.getInstance();
    final jsonList = stations.map((station) => station.toJson()).toList();
    await prefs.setString(favouriteKey, jsonEncode(jsonList));
  }

  static Future<List<MetroStation>> getFavourites() async {
    final prefs = await SharedPreferences.getInstance();
    final jsonString = prefs.getString(favouriteKey);
    if (jsonString == null) return [];
    final jsonList = jsonDecode(jsonString) as List<dynamic>;
    return jsonList.map((json) => MetroStation.fromJson(json as Map<String, dynamic>)).toList();
  }
}

5. 修正UI中的异步调用逻辑

确保先完成存储再读取数据:

setState(() {
  if (station.isFavourite) {
    favouriteData.remove(station);
    station.isFavourite = false;
  } else {
    favouriteData.add(station);
    station.isFavourite = true;
  }
  // 调试打印
  debugPrint('-----------');
  for (var element in favouriteData) {
    debugPrint(element.ukrName);
  }
  debugPrint('-----------');
});

// 等待存储完成后再读取
await SharedPref.saveFavourites(favouriteData);
final savedFavourites = await SharedPref.getFavourites();
print(savedFavourites.map((s) => s.ukrName).toList());

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:10:19