Flutter中如何向SharedPreferences存储完整对象列表而非单个变量
搜索历史功能修复方案
问题根源
你的代码存在几个关键问题导致只能保存单个搜索记录:
- 语法错误导致逻辑执行异常(比如
Final应为小写final、方法命名和参数不匹配) SearchDelegateMenuPrincipal中初始化历史的方法未正确触发且未更新UI- 展示历史的组件中存在类型错误(直接访问字符串列表的
apodo属性)
修复后的完整代码
class BBC extends StatefulWidget { @override State<BBC> createState() => _BBCState(); } class _BBCState extends State<BBC> { List<SearchDelegateModel> historialMenuPrincipal = []; @override void initState() { super.initState(); _cargarHistorial(); } // 初始化加载本地存储的搜索历史 Future<void> _cargarHistorial() async { SharedPreferences prefs = await SharedPreferences.getInstance(); List<String>? nombresHistorial = prefs.getStringList("HistorialBusquedaPreferences"); if (nombresHistorial != null) { setState(() { historialMenuPrincipal = nombresHistorial.map((apodo) => SearchDelegateModel(apodo: apodo)).toList(); }); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( actions: [ IconButton( icon: Icon(Icons.search), onPressed: () async { SharedPreferences prefs = await SharedPreferences.getInstance(); final busqueda = await showSearch( context: context, delegate: SearchDelegateMenuPrincipal("Buscar...", historialMenuPrincipal) ); if (busqueda != null) { setState(() { // 移除重复记录 historialMenuPrincipal.removeWhere((item) => item.apodo == busqueda.apodo); // 新记录插入到最前面 historialMenuPrincipal.insert(0, busqueda); }); // 将完整的历史列表转成字符串列表存储 List<String> nombres = historialMenuPrincipal.map((e) => e.apodo!).toList(); await prefs.setStringList("HistorialBusquedaPreferences", nombres); // 打印完整历史列表验证 var getpre = prefs.getStringList("HistorialBusquedaPreferences"); print("完整搜索历史: $getpre"); } }, ) ], ), ); } } class SearchDelegateMenuPrincipal extends SearchDelegate<SearchDelegateModel> { List<SearchDelegateModel> historialMenuPrincipal; List<String> historialbusquedapreferences = []; SearchDelegateMenuPrincipal(String hintText, this.historialMenuPrincipal) : super(searchFieldLabel: hintText); @override void initState() { super.initState(); _cargarHistorial(); } Future<void> _cargarHistorial() async { SharedPreferences prefs = await SharedPreferences.getInstance(); historialbusquedapreferences = prefs.getStringList("HistorialBusquedaPreferences") ?? []; // 通知UI更新 query = query; } @override Widget buildSuggestions(BuildContext context) { return historialbusquedapreferences.isEmpty ? MensajeHistorialBusquedaVacio() : HistorialBusqueda2(context, historialbusquedapreferences); } @override Widget buildLeading(BuildContext context) { return IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => close(context, SearchDelegateModel(apodo: "")), ); } @override Widget buildResults(BuildContext context) { // 根据你的需求实现搜索结果展示 return Container(); } } Widget HistorialBusqueda2(BuildContext context, List<String> historial) { return ListView.builder( itemCount: historial.length, itemBuilder: (context, i) { return ListTile( leading: Text(historial[i] ?? "no data"), onTap: () { // 点击历史记录时的逻辑 (context as SearchDelegate).close(context, SearchDelegateModel(apodo: historial[i])); }, ); }, ); } Widget MensajeHistorialBusquedaVacio() { return Center(child: Text("暂无搜索历史")); } class SearchDelegateModel { String? apodo; String? name; SearchDelegateModel({this.apodo, this.name}); factory SearchDelegateModel.fromJson(Map<String, dynamic> parsedJson) { return SearchDelegateModel( name: parsedJson['Name'], apodo: parsedJson['Apodo'], ); } }
关键修复点
- 初始化加载历史:在
BBC的initState和SearchDelegateMenuPrincipal的initState中分别加载本地存储的历史,确保页面打开时能显示已有记录 - 修复语法错误:修正
Final为final、方法命名空格问题、参数传递错误 - 正确更新UI:使用
setState更新本地列表,在SearchDelegate中通过更新query触发UI重建 - 类型匹配:展示历史时直接使用字符串列表中的值,避免错误访问对象属性
- 完整存储逻辑:每次添加新记录后,将完整的历史列表转成字符串列表存入SharedPreferences,而不是仅存单个值
内容的提问来源于stack exchange,提问作者Anes
相关产品推荐
相关产品推荐

