Flutter异步调用中setState()不生效问题求助
Fixing Your Flutter JSON Loading Issue
Let's break down the problems in your code and walk through how to fix them so your _data list updates correctly after loading the JSON file.
Key Issues in Your Current Code
- Async Timing Mismatch: When you call
getData()ininitState(), it runs asynchronously—but you immediately print_data.lengthright after calling it. At that point, the file hasn't been read yet, so_datais still empty. - No Error Handling: If the
mood.jsonfile doesn't exist, has invalid JSON, or the path is wrong, your code will crash without any feedback. - Blocking UI with Synchronous Read: Using
readAsStringSync()blocks the UI thread while reading the file, which can cause jank in your app.
Fixed Code with Explanations
Here's the revised version of your code with fixes for all the above issues:
import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; class DisplayPage extends StatefulWidget { @override _DisplayPageState createState() => _DisplayPageState(); } class _DisplayPageState extends State<DisplayPage> { List _data = []; Directory? dir; File? jsonFile; String? jsonPath; Future<void> getData() async { try { // Get app documents directory asynchronously dir = await getApplicationDocumentsDirectory(); jsonPath = "${dir!.path}/mood.json"; jsonFile = File(jsonPath!); // First check if the file exists to avoid errors if (await jsonFile!.exists()) { // Use async file read to avoid blocking UI String jsonContent = await jsonFile!.readAsString(); final parsedData = json.decode(jsonContent); // Ensure the parsed data is a List before updating state if (parsedData is List) { setState(() { _data = parsedData; }); print("Successfully loaded ${_data.length} items"); } else { print("Error: JSON content is not a List"); } } else { print("mood.json does not exist in the documents directory"); } } catch (e) { // Catch any errors during file read or JSON parsing print("Failed to load data: $e"); } } @override void initState() { super.initState(); // Wait for getData to complete before checking data length getData().then((_) { print(_data.length); // This will show the correct count now }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Mood'), ), // Show a fallback UI when data is empty body: _data.isEmpty ? const Center(child: Text("No mood data available")) : ListView.builder( itemCount: _data.length, itemBuilder: (BuildContext context, int index) { // Add a null check for the "title" field to avoid crashes return Card( child: Text(_data[index]["title"] ?? "Untitled"), ); }, ), ); } }
What Changed?
- Async/Await Fix: We added a
.then()callback togetData()ininitState()so we only print the data length after the async operation finishes. - Error Handling: Wrapped all file operations and JSON parsing in a
try-catchblock to catch and log errors instead of crashing. - Async File Read: Replaced
readAsStringSync()withawait readAsString()to keep the UI responsive. - Safety Checks: Added checks to verify the file exists and that the parsed JSON is actually a List before updating
_data. - Fallback UI: Added a simple message when
_datais empty, so users don't see a blank screen.
内容的提问来源于stack exchange,提问作者nujabse




