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

Flutter调用API数据无法加载,加载指示器一直处于运行状态如何修复?

问题原因

  • 首先是返回类型不匹配:你的getLiveMatches方法声明返回Future<List<dynamic>>,但你调用的API返回的liveMatch字段是Map类型,不是列表,类型转换失败会抛出异常,而你没有在FutureBuilder里处理异常情况,所以hasData始终为false,加载指示器一直显示。
  • 其次是FutureBuilder未覆盖全状态:你只判断了snapshot.hasData的情况,没有处理加载完成但有错误的分支,异常被吞了自然看不到问题。
  • 最后是future调用方式不规范:直接在FutureBuilder的future参数里调用getLiveMatches(),每次组件重绘都会重新发起请求,同时RefreshIndicator的刷新逻辑没有触发状态更新,刷新后也不会刷新界面。

修复后的完整代码

import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class Test extends StatefulWidget {
  const Test({super.key});

  @override
  State<Test> createState() => _TestState();
}

class _TestState extends State<Test> {
  // 提前声明future变量,避免每次build重复请求
  late Future<Map<String, dynamic>> _liveMatchFuture;

  Future<Map<String, dynamic>> getLiveMatches() async {
    http.Response response = await http.get(
        Uri.parse("https://api.cricket.com.au/matches/2780/50837/live")
    );
    final Map parseData = json.decode(response.body);
    var matches  = parseData['liveMatch'];
    // 确认返回类型是Map,和方法声明一致
    return matches;
  }

  @override
  void initState() {
    super.initState();
    // 初始化时只请求一次
    _liveMatchFuture = getLiveMatches();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.only(left: 10, right: 10, top: 15),
        child: RefreshIndicator(
          color: Colors.white,
          backgroundColor: Colors.purple,
          strokeWidth: 5,
          onRefresh: ()async{
            // 刷新时重新请求,调用setState更新future触发重绘
            setState(() {
              _liveMatchFuture = getLiveMatches();
            });
            // 等待请求完成再结束刷新动画
            await _liveMatchFuture;
          },
          child: Container(
            height: double.infinity,
            decoration: const BoxDecoration(
                borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(6),
                    topRight: Radius.circular(6)
                ),
                color: Colors.white
            ),
            child: FutureBuilder<Map<String, dynamic>>(
                future: _liveMatchFuture,
                builder: (context, snapshot) {
                  // 处理加载中状态
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return const Center(
                        child: CupertinoActivityIndicator(
                            animating: true, radius: 10));
                  }
                  // 处理错误状态
                  if (snapshot.hasError) {
                    return Center(
                      child: Text('加载出错:${snapshot.error}'),
                    );
                  }
                  // 正常返回数据的情况
                  Map<String, dynamic> match = snapshot.data!;
                  return SingleChildScrollView(
                    // 因为内容可能超出屏幕,加滚动同时适配RefreshIndicator的滚动要求
                    child: Column(
                      children: [
                        Text(match.toString())
                      ],
                    ),
                  );
                }
            ),
          ),
        ),
      ),
    );
  }
}

补充说明

  • 如果你后续需要展示多条赛事数据,确认API返回字段的类型后再调整返回值类型即可,不要强行把Map转成List。
  • 加了SingleChildScrollView是因为RefreshIndicator要求子组件是可滚动组件,之前你用Container作为子组件,下拉刷新的手势也会失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 16:09:03