Flutter启动时加载JSON数据:Provider重建致已加载数据丢失的问题解决咨询
问题根源分析
你遇到的核心问题是创建了两个完全独立的QuestionProvider实例:
- 在
initState里,你实例化了一个临时的QuestionProvider并调用了loadJsonFiles(),数据加载到了这个实例的questionList里; - 但在
MultiProvider的create方法中,你又新建了一个全新的QuestionProvider,这个实例的questionList是空的,自然就看不到之前加载的数据了。
解决方案:复用同一个Provider实例
我们只需要在initState时创建并初始化好QuestionProvider实例,之后在MultiProvider中直接复用这个实例,而不是重新创建。这样数据就会保存在同一个实例的列表中,不会被清空。
修改后的完整代码
void main() { runApp(const MyApp()); } class MyApp extends Stateful Widget { const MyApp({Key? key}) : super(key: key); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { late Future<void> _initFuture; late QuestionProvider _questionProvider; // 保存Provider实例 @override void initState() { super.initState(); _questionProvider = QuestionProvider(); // 初始化同一个实例 _initFuture = _questionProvider.loadJsonFiles(); // 用这个实例加载数据 } @override Widget build(BuildContext context) { return FutureBuilder( future: _initFuture, builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const MaterialApp(home: Splash()); } else { return MultiProvider( providers: [ // 直接传入已初始化好的实例,而不是重新创建 ChangeNotifierProvider.value(value: _questionProvider), ], child: MaterialApp( title: "MyApp", theme: ThemeData( primarySwatch: Colors.amber, ), home: const Home(), ) ); } }, ); } } class QuestionProvider with ChangeNotifier { final List<QuestionModel> questionList = <QuestionModel>[]; Future<void> loadJsonFiles() async { final String response = await rootBundle.loadString("assets/questions.json"); final Map<String, dynamic> data = await jsonDecode(response); // 先清空列表(防止重复加载时数据重复) questionList.clear(); for (int i = 0; i < data.length; i++) { questionList.add(QuestionModel.fromJson(data[i])); } // 加载完成后通知监听者(如果后续页面需要响应数据变化的话) notifyListeners(); } }
关键修改点说明
- 保存Provider实例:在
_MyAppState中声明_questionProvider变量,在initState中初始化,确保整个生命周期只使用这一个实例。 - 使用
ChangeNotifierProvider.value:在MultiProvider中不再通过create新建实例,而是用value传入已初始化好的_questionProvider。 - 添加
notifyListeners():数据加载完成后调用这个方法,确保依赖该Provider的页面能及时获取到最新数据(如果你的Home页面需要监听数据变化的话)。 - 清空列表防重复:在
loadJsonFiles开头添加questionList.clear(),避免后续如果重新调用该方法时数据重复累积。
另一种思路:在Provider内部处理初始化
如果你不想在State中保存实例,也可以让Provider自己处理初始化逻辑,同时确保初始化只执行一次:
class QuestionProvider with ChangeNotifier { final List<QuestionModel> questionList = <QuestionModel>[]; bool _isInitialized = false; Future<void> initialize() async { if (_isInitialized) return; // 防止重复初始化 final String response = await rootBundle.loadString("assets/questions.json"); final Map<String, dynamic> data = await jsonDecode(response); questionList.clear(); for (int i = 0; i < data.length; i++) { questionList.add(QuestionModel.fromJson(data[i])); } _isInitialized = true; notifyListeners(); } }
然后在initState中:
@override void initState() { super.initState(); _questionProvider = QuestionProvider(); _initFuture = _questionProvider.initialize(); }
这种方式更符合单一职责原则,把数据初始化的逻辑封装在Provider内部。
内容的提问来源于stack exchange,提问作者Printer
相关产品推荐
相关产品推荐

