You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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() in initState(), it runs asynchronously—but you immediately print _data.length right after calling it. At that point, the file hasn't been read yet, so _data is still empty.
  • No Error Handling: If the mood.json file 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?

  1. Async/Await Fix: We added a .then() callback to getData() in initState() so we only print the data length after the async operation finishes.
  2. Error Handling: Wrapped all file operations and JSON parsing in a try-catch block to catch and log errors instead of crashing.
  3. Async File Read: Replaced readAsStringSync() with await readAsString() to keep the UI responsive.
  4. Safety Checks: Added checks to verify the file exists and that the parsed JSON is actually a List before updating _data.
  5. Fallback UI: Added a simple message when _data is empty, so users don't see a blank screen.

内容的提问来源于stack exchange,提问作者nujabse

火山引擎 最新活动