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

Flutter首次加载API返回null 热重载后正常获取数据问题

问题原因

你遇到的首次加载一直显示加载态、热重载后才正常显示数据的问题,是三处代码写法错误共同导致的:

  • initState是Flutter框架同步调用的生命周期方法,不能加async关键字。加了async后,方法内的异步逻辑不会被框架等待,第一次页面渲染执行时,接口请求还没返回,data必然是null。
  • 你把接口请求方法getData、请求地址url的定义全写在了build方法内部,而且请求拿到返回值后,把触发页面刷新的setState(() {})代码注释掉了。就算接口请求成功拿到了数据,没有调用setState通知框架重绘,页面会一直停留在初始的加载状态。
  • initState中调用getData()时没有加await关键字,就算initState支持异步执行,不await的话调用完请求方法会直接往下走渲染逻辑,不会等接口返回再更新页面。
    另外你在类中已经定义了url成员变量,又在build方法里定义了同名的局部url变量,属于容易引发逻辑混乱的冗余写法。
修正方案

把数据请求逻辑、url初始化全部挪到build方法外,用正确的生命周期写法处理异步请求,拿到数据后通过setState触发页面刷新,修正后的核心代码如下:

// 原有import代码保持不变即可
class Profile extends StatefulWidget {
  var usrid;
  Profile({Key? key, @required this.usrid}) : super(key: key);

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

class _Profile extends State<Profile>{
  var data;
  late Uri requestUrl;

  @override
  void initState(){
    super.initState();
    // 初始化请求地址
    requestUrl = Uri.https(
      'www.******.net', 
      '/mm_api/index.php',
      {'act':'profile','UsrID': widget.usrid}
    );
    // 触发数据加载
    _loadProfileData();
  }

  // 数据请求方法作为类成员方法,不要写在build内部
  Future<void> _loadProfileData() async{
    try{
      final res = await http.get(
        requestUrl,
        headers: {'Content-Type': 'application/json'},
      );
      // 先判断请求状态码是否正常
      if(res.statusCode == 200){
        final resData = jsonDecode(res.body);
        // 赋值后必须调用setState触发页面重绘
        setState(() {
          data = resData;
        });
      }
    }catch(e){
      // 可在此处添加网络错误、接口报错的提示逻辑
      debugPrint('个人资料请求失败: $e');
    }
  }

  @override
  Widget build(BuildContext context){
    final UsrID = widget.usrid;
    final Size size = MediaQuery.of(context).size;
    final double padding = 25;
    final sidePadding = EdgeInsets.symmetric(horizontal: padding);

    return Scaffold(
      appBar: AppBar(
        titleSpacing: 3,
        backgroundColor: Colors.white,
        elevation: 0,
        title: const Text('My Profile', style: TextStyle(color: Colors.black, fontSize: 15,),),
        leading: Builder(
          builder: (BuildContext context) {
            return Padding(
              padding: const EdgeInsets.fromLTRB(15, 0, 0, 0),
              child: IconButton(
                icon: SvgPicture.asset(
                  width: 30,
                  'assets/images/Menu.svg',
                  height: 30,
                ),
                onPressed: () { Scaffold.of(context).openDrawer(); },
                tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
              ),
            );
          },
        ),
        actions: <Widget>[
          Padding(
              padding: sidePadding,
              child: Row(
                children: [
                  SvgPicture.asset(
                    width: 30,
                    'assets/images/search.svg',
                    height: 30,
                  ),
                ],
              )
          )
        ],
      ),
      backgroundColor: const Color(0xff8f9df2),
      body: Container(
          decoration: const BoxDecoration(
            gradient: LinearGradient(
                begin: Alignment.topRight,
                end: Alignment.bottomLeft,
                colors: [Colors.white, Colors.white]
            ),
          ),
          width: size.width,
          height: size.height,
          child: Stack(
            children: [
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  data != null?Expanded(
                      child: Padding(
                        padding: sidePadding,
                        child: ListView(
                          physics: const BouncingScrollPhysics(),
                          children: [
                            Text('${data[0]['name']}')
                          ],
                        ),
                      )
                  ): const Center(
                    child: CircularProgressIndicator(),
                  )
                ],
              ),
            ],
          )
      ),
      drawer: Sidebar(),
      persistentFooterButtons: [
        Footer(usrid:UsrID),
      ],
    );
  }
}
开发注意事项
  • 不要给initState、build这类Flutter框架内置的生命周期方法加async关键字,这类方法的执行时序由框架控制,加异步标记会打破原有执行流程,引发时序类bug。
  • 不要把数据请求、全局变量定义这类和UI构建无关的逻辑写在build方法中。只要页面触发重绘(比如键盘弹出、屏幕旋转、setState调用),build内的所有代码都会重新执行,会导致重复发请求、性能损耗、逻辑混乱等问题。
  • 调用setState更新状态前,要保证当前组件已经挂载,页面销毁后不要继续调用setState,避免内存泄漏。
  • 网络请求必须加异常捕获和状态码校验,避免网络异常、接口报错时直接出现白屏、崩溃问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:30:49