You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中Map<String, dynamic>始终为空的原因排查

Flutter异步请求后dataList始终为空的问题排查与解决

问题描述

我编写了Flutter代码定义了Structure类,其中readData方法通过HTTP请求从USDA API获取数据并赋值给dataList。但在其他文件中导入该类并调用readData后,Map<String, dynamic>类型的dataList始终为空。尝试直接调用readData以及在setState中调用该方法,结果都一样。

原代码如下:

import 'package:http/http.dart' as http;
import 'dart:convert';

class Structure {
  Map<String, dynamic> dataList = <String, dynamic>{};
  final String apiKey = "Dx6Raz0w6yVEEilPlk2edTmDSJBvTJh7qkou7OwW";
  String query = "Cheddar Cheese";
  String dataType = "SR Legacy";
  String pageSize = "25";
  String pageNumber = "2";
  String sortBy = "publishedDate";
  String sortOrder = "asc";

  Future<void> readData() async {
    query.replaceAll(' ', '%20');
    dataType.replaceAll(' ', '%20');
    String request =
        "https://api.nal.usda.gov/fdc/v1/foods/search?query=$query&dataType=$dataType&pageSize=$pageSize&pageNumber=$pageNumber&sortBy=$sortBy&sortOrder=$sortOrder&api_key=$apiKey";

    final response = await http.get(Uri.parse(request));

    if (response.statusCode == 200) {
      Map<String, dynamic> data = jsonDecode(response.body);
      dataList = data;
    } else {
      throw Exception('Failed to fetch data');
    }
  }
}

调用代码:

Structure s = Structure();
s.readData();
print('$s.dataList');

以及:

Structure s = Structure();
setState(() {s.readData();});
print('$s.dataList');

原因分析

  1. 异步操作执行顺序错误
    readData是异步方法(返回Future<void>),调用它后会立刻继续执行后续的print语句,此时HTTP请求还没完成,dataList自然还是初始的空Map。哪怕把readData放进setState里,setState也不会等待异步方法完成,print依然会提前执行。

  2. 字符串替换操作无效
    Dart中的String是不可变类型,replaceAll方法不会修改原字符串,而是返回一个新的字符串。原代码里query.replaceAll(' ', '%20')没有把返回值赋值给query,导致URL里的空格没有被转义,可能直接导致请求失败,即便等异步完成也拿不到数据。

解决办法

1. 正确等待异步操作完成

调用readData时必须用await等待其执行完毕,才能确保dataList已经被赋值。如果是在Widget的方法里,需要把方法标记为async:

// 示例调用(需在async方法中执行)
Structure s = Structure();
await s.readData();
print(s.dataList);

2. 修复字符串转义问题

将replaceAll的返回值赋值给原变量,或者更推荐用Uri.encodeComponent来处理URL参数的转义,避免手动处理出错:

Future<void> readData() async {
  // 方式1:接收replaceAll的返回值
  // query = query.replaceAll(' ', '%20');
  // dataType = dataType.replaceAll(' ', '%20');
  
  // 方式2:更安全的URL参数转义
  String request =
      "https://api.nal.usda.gov/fdc/v1/foods/search?query=${Uri.encodeComponent(query)}&dataType=${Uri.encodeComponent(dataType)}&pageSize=$pageSize&pageNumber=$pageNumber&sortBy=$sortBy&sortOrder=$sortOrder&api_key=$apiKey";

  final response = await http.get(Uri.parse(request));

  if (response.statusCode == 200) {
    Map<String, dynamic> data = jsonDecode(response.body);
    dataList = data;
  } else {
    throw Exception('Failed to fetch data');
  }
}

3. 在Widget中正确更新UI

如果是在Widget里使用,不要把异步方法放进setState,而是在异步方法完成后调用setState来更新UI:

Structure s = Structure();

// 在State类的方法中
void fetchData() async {
  await s.readData();
  setState(() {
    // 这里dataList已经有值,可以更新UI
  });
}

// 调用fetchData而不是直接调用readData
fetchData();

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 02:53:17