Flutter中SharedPreferences搜索历史展示报错求助
问题分析与解决方案
核心错误原因
- 类型不匹配:将
BModel对象转成String存储后,读取时直接把String列表当成BModel列表使用,historialbusquedapreferences[i]是String类型,没有edad属性,调用.edad必然触发错误。 - 初始化方法未执行:
InitRetornarHistorialB方法从未被调用,导致historialbusquedapreferences始终是空列表,触发索引越界。 - 对象序列化错误:直接用默认
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
相关产品推荐
相关产品推荐

