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

Flutter调用API获取数据后页面显示空白屏幕问题求助

问题根因

页面显示空白/持续加载是4处逻辑错误导致的:

  • 结果页API实例未初始化:ResultsPage中声明的_APIState? api从未赋值,initState执行objectList = api?.signInData()时,因为api为null,最终objectList被赋值为null。FutureBuilder绑定null的future后,永远等不到数据返回,自然无法渲染内容。
  • 跳转时机完全错误:你在signInData方法中检测到200状态码就立刻跳转结果页,既没有等待接口数据解析完成,也没有把解析到的车辆数据传递给结果页,后续return CarDetails.fromJson(...)的返回值没有任何组件接收,等于白解析。
  • 500状态码递归请求丢失返回值:接口返回500刷新token后,你递归调用了signInData()但没有加return,递归执行拿到的请求结果会被直接丢弃,就算刷新token后请求成功也拿不到数据。
  • 重复解析响应:dio默认会自动将json格式的响应体转成Map类型,你额外调用jsonDecode(response.data.toString())属于重复解析,在部分响应格式场景下会直接抛异常,导致Future进入error状态但你没做错误日志捕获。
修复方案

推荐用第一种方案,逻辑更简单,避免重复请求。

方案1:请求完成拿到数据后再跳转,通过路由参数传值

第一步:调整signInData方法逻辑,先拿数据再跳转

Future<CarDetails?> signInData() async {
    final prefs = await SharedPreferences.getInstance();
    final String? token = prefs.getString('token');

    try {
      Response response = await _dio.post('$_baseUrl/api/gateway',
          data: {
            "ClientPackageId": "0cdd231a-d7ad-4a68-a934-d373affb5100",
            "PlatformId": "ios",
            "ClientUserId": "AhmedOmar",
            "VinNumber": VINumber
          },
          options: Options(headers: {
            "Content-Type": "application/json",
            "Authorization": "Bearer $token",
          }));
      print("接口返回:${response.data},状态码:${response.statusCode}");
      
      if (response.statusCode == 200) {
        // 先解析数据
        CarDetails carData = CarDetails.fromJson(response.data);
        // 校验组件挂载状态再跳转,避免内存泄漏
        if(mounted){
          Navigator.of(context).pushReplacement(
            MaterialPageRoute(
              builder: (context) => ResultsPage(carDetail: carData),
            ),
          );
        }
        return carData;
      }
      else if (response.statusCode == 500) {
        await getToken();
        // 加return,把递归请求的结果返回
        return signInData();
      }
      // 其他状态码直接抛异常
      throw Exception("请求失败,状态码${response.statusCode}");
    } catch (e) {
      print("请求异常:$e");
      rethrow;
    }
}

第二步:修改ResultsPage,接收路由参数直接渲染

class ResultsPage extends StatefulWidget {
  final CarDetails carDetail;
  const ResultsPage({Key? key, required this.carDetail}) : super(key: key);

  @override
  _ResultsPageState createState() => _ResultsPageState();
}

class _ResultsPageState extends State<ResultsPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Text(widget.carDetail.make ?? "未获取到车辆厂商信息"),
      ),
    );
  }
}

方案2:在结果页发起请求(不推荐)

如果要把请求逻辑放在结果页,首先要删掉signInData方法里200状态码下的跳转逻辑,其次不要把请求方法写在State子类里(State类和组件生命周期绑定,独立实例化会丢context和状态),把网络请求抽离到独立的服务类中,再在结果页初始化实例发起请求:

// 结果页initState修正示例
@override
void initState() {
  super.initState();
  // 替换为你自己的请求服务类实例
  final api = ApiService();
  objectList = api.signInData();
}

注意:不要在build方法里初始化Future,否则每一次组件重绘都会重新发起请求,浪费流量和性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 00:54:27