Flutter中Provider函数外访问变量异常:收藏列表刷新后为空
问题原因
当前你的MyAppProvider中selectedItems仅存储在内存里,App重启(包括热重启/刷新)后内存数据会被清空,所以刷新后进入收藏页面会得到空数组。
修复方案
要解决这个问题,需要将收藏数据持久化到本地存储,下面提供两种常用实现方式:
方案一:使用SharedPreferences(适合简单数据结构)
1. 添加依赖
在pubspec.yaml中添加:
dependencies: shared_preferences: ^2.2.2
执行flutter pub get安装依赖。
2. 改造Provider类
修改my_provider.dart,添加本地存储的读写逻辑:
import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; class MyAppProvider extends ChangeNotifier { List<Items> selectedItems = []; MyAppProvider() { // 初始化时加载本地存储的收藏数据 _loadFavorites(); } void addItems(Items items) { selectedItems.add(items); _saveFavorites(); // 保存到本地 notifyListeners(); } List<Items> getSelectedItems() { return selectedItems; } // 将收藏列表保存到本地 Future<void> _saveFavorites() async { final prefs = await SharedPreferences.getInstance(); // 把Items列表转为JSON字符串(需要Items类实现toJson方法) final jsonData = jsonEncode(selectedItems.map((item) => item.toJson()).toList()); await prefs.setString('favorites', jsonData); } // 从本地加载收藏数据 Future<void> _loadFavorites() async { final prefs = await SharedPreferences.getInstance(); final savedData = prefs.getString('favorites'); if (savedData != null) { final List<dynamic> jsonList = jsonDecode(savedData); selectedItems = jsonList.map((json) => Items.fromJson(json)).toList(); notifyListeners(); } } }
3. 给Items类添加JSON序列化方法
确保你的Items类实现toJson和fromJson:
class Items { final String id; final String name; // 其他属性... Items({required this.id, required this.name}); // 转为JSON格式 Map<String, dynamic> toJson() { return { 'id': id, 'name': name, // 其他属性对应添加 }; } // 从JSON解析为Items对象 factory Items.fromJson(Map<String, dynamic> json) { return Items( id: json['id'], name: json['name'], // 其他属性对应解析 ); } }
方案二:使用Hive(适合复杂数据结构,性能更优)
1. 添加依赖
在pubspec.yaml中添加:
dependencies: hive: ^2.2.3 hive_flutter: ^1.1.0 dev_dependencies: build_runner: ^2.4.6
执行flutter pub get安装依赖。
2. 配置Items类并生成适配器
给Items类添加Hive注解,生成适配器:
import 'package:hive/hive.dart'; part 'items.g.dart'; @HiveType(typeId: 0) // 唯一typeId,多个类不能重复 class Items extends HiveObject { @HiveField(0) final String id; @HiveField(1) final String name; // 其他属性... Items({required this.id, required this.name}); }
运行命令生成适配器:
flutter pub run build_runner build
3. 初始化Hive(在main函数中)
import 'package:flutter/material.dart'; import 'package:hive_flutter/hive_flutter.dart'; void main() async { await Hive.initFlutter(); Hive.registerAdapter(ItemsAdapter()); // 注册适配器 await Hive.openBox<Items>('favorites'); // 打开存储收藏的盒子 runApp(const MyApp()); }
4. 改造Provider类
import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; class MyAppProvider extends ChangeNotifier { late Box<Items> _favoritesBox; List<Items> selectedItems = []; MyAppProvider() { _favoritesBox = Hive.box<Items>('favorites'); _loadFavorites(); } void addItems(Items items) { _favoritesBox.add(items); // 直接存入Hive _loadFavorites(); notifyListeners(); } List<Items> getSelectedItems() { return selectedItems; } void _loadFavorites() { selectedItems = _favoritesBox.values.toList(); } }
额外代码修正
favorites.dart中Class改为小写class,类名遵循大驼峰命名改为Favorites- 移除
listen: false(默认listen: true),这样收藏页面能实时响应Provider的数据变化:
class Favorites extends StatelessWidget { const Favorites({super.key}); @override Widget build(BuildContext context) { List<Items> favoriteList = Provider.of<MyAppProvider>(context).getSelectedItems(); print(favoriteList); // 示例:用ListView展示收藏内容 return ListView.builder( itemCount: favoriteList.length, itemBuilder: (context, index) { return ListTile( title: Text(favoriteList[index].name), ); }, ); } }
内容的提问来源于stack exchange,提问作者Christina
相关产品推荐
相关产品推荐

