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

Flutter中SharedPreferences搜索历史展示报错求助

问题分析与解决方案

核心错误原因

  1. 类型不匹配:将BModel对象转成String存储后,读取时直接把String列表当成BModel列表使用,historialbusquedapreferences[i]是String类型,没有edad属性,调用.edad必然触发错误。
  2. 初始化方法未执行:InitRetornarHistorialB方法从未被调用,导致historialbusquedapreferences始终是空列表,触发索引越界。
  3. 对象序列化错误:直接用默认toString()转BModel为String,输出内容不是可解析的JSON格式,无法还原成BModel对象。

修复步骤

1. 正确序列化/反序列化BModel对象

替换默认toString(),将BModel转成JSON字符串存储,读取后再解析回BModel:

// ABC类中修改存储逻辑
historialbusquedacasteada = historialMenuPrincipal.map((e) => json.encode(e.toJson())).toList();
prefs.setStringList("HistorialBusquedaPreferences", historialbusquedacasteada);

// 给BModel类添加toJson方法
class BModel{
  String edad;
  BModel({this.edad});
  
  factory BModel.fromJson(Map<String, dynamic> parsedJson){
    return BModel(
      edad: parsedJson['edad'],
    );
  }

  // 新增序列化方法
  Map<String, dynamic> toJson() {
    return {
      'edad': edad,
    };
  }
}

2. 修正历史记录读取逻辑

修改SearchB类,将读取的字符串列表解析为BModel列表:

class SearchB extends SearchDelegate<BModel> {
  // 改为BModel类型列表
  List<BModel> historialbusquedapreferences = [];

  Future<void> InitRetornarHistorialB() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    List<String>? jsonStrings = prefs.getStringList("HistorialBusquedaPreferences");
    if (jsonStrings != null) {
      historialbusquedapreferences = jsonStrings.map((str) => BModel.fromJson(json.decode(str))).toList();
    }
  }

  // ...其他代码
}

3. 确保初始化方法执行并刷新UI

在buildSuggestions中用FutureBuilder处理异步初始化,保证数据加载完成后再渲染:

@override
Widget buildSuggestions(BuildContext context) {
  return FutureBuilder(
    future: InitRetornarHistorialB(),
    builder: (context, snapshot) {
      if (snapshot.connectionState == ConnectionState.waiting) {
        return Center(child: CircularProgressIndicator());
      }
      return historialbusquedapreferences.isEmpty 
          ? MensajeHistorialBusquedaVacio()
          : HistorialBusqueda2(context);
    },
  );
}

4. 修正历史记录渲染方法

现在historialbusquedapreferences是BModel列表,直接访问edad属性:

Widget HistorialBusqueda2(BuildContext context) {
  return Container(
    child: StatefulBuilder(
      builder: (context, setState) {
        return Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: historialbusquedapreferences.length,
                itemBuilder: (context, i) {
                  return ListTile(
                    title: EdadHistorialBusqueda(i),
                  );
                },
              ),
            ),
          ],
        );
      },
    ),
  );
}

Widget EdadHistorialBusqueda(int i){
  return Container(
    child: CircleAvatar(
      radius: 28,
      foregroundImage: NetworkImage("http://...${historialbusquedapreferences[i].edad}"),
    ),
  );
}

5. 边界情况处理

通过FutureBuilder和isEmpty判断,确保空列表时不会进入ListView渲染逻辑,避免索引越界。

额外注意事项

  • 调用setStringList前可添加空列表判断,避免存储null值。
  • 已实现的历史记录去重逻辑(removeWhere)可保留,避免重复条目。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 00:55:09