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

Flutter中getApiKey方法循环调用的原因及解决办法

问题原因及解决办法

嘿,我来帮你拆解下这个getApiKey()持续循环调用的问题~

为什么会出现循环?

你在MyTestWidget的build方法里直接调用了Provider.of<TenderApiData>(context).getApiKey(),而build方法本身会在以下场景被触发:

  • 组件首次渲染
  • 依赖的ChangeNotifier调用notifyListeners()(也就是你获取到API密钥后触发的通知)

当getApiKey()成功获取到密钥并调用notifyListeners()时,会触发MyTestWidget重新执行build方法,而build里又会再次调用getApiKey(),如此循环往复,就形成了无限调用的死循环。

另外还有个小问题:build方法应该是纯无副作用的函数,不应该在里面发起网络请求这类有副作用的操作,因为Flutter可能会频繁触发build(比如屏幕旋转、父组件更新等),这会导致不必要的重复请求。

解决办法

这里给你几个可行的方案,任选其一都能解决问题:

方案1:将组件改为StatefulWidget,在initState里发起请求

initState是StatefulWidget的生命周期方法,只会在组件初始化时执行一次,刚好适合这种只需要执行一次的网络请求:

class MyTestWidget extends StatefulWidget {
  @override
  _MyTestWidgetState createState() => _MyTestWidgetState();
}

class _MyTestWidgetState extends State<MyTestWidget> {
  @override
  void initState() {
    super.initState();
    // 这里要加listen: false,因为initState里不需要监听状态变化
    Provider.of<TenderApiData>(context, listen: false).getApiKey();
  }

  @override
  Widget build(BuildContext context) {
    var result = Provider.of<TenderApiData>(context).access_token;
    return Row(
      children: <Widget>[
        Flexible(child: Text("Data: $result"))
      ],
    );
  }
}

方案2:在TenderApiData的构造函数里初始化请求

把数据获取逻辑放在状态类的构造函数里,这样当TenderApiData被实例化时就自动发起请求,不需要在组件里调用:

class TenderApiData with ChangeNotifier {
  String access_token;
  String url = "https://";

  // 构造函数里调用getApiKey
  TenderApiData() {
    getApiKey();
  }

  getApiKey() async {
    var response = await http.post(url, headers: {"Accept": "application/json"});
    if (response.statusCode == 200) {
      access_token = json.decode(response.body)['access_token'];
      notifyListeners();
    }
  }
}

// 然后MyTestWidget的build里只需要获取数据即可,不用调用getApiKey()
class MyTestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var result = Provider.of<TenderApiData>(context).access_token;
    return Row(
      children: <Widget>[
        Flexible(child: Text("Data: $result"))
      ],
    );
  }
}

方案3:使用Consumer优化组件监听

如果你想保持组件为StatelessWidget,也可以用Consumer来监听状态变化,同时把请求逻辑放在合适的地方(比如父组件的初始化里),这样能避免不必要的build触发:

class MyTestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<TenderApiData>(
      builder: (context, apiData, child) {
        return Row(
          children: <Widget>[
            Flexible(child: Text("Data: ${apiData.access_token}"))
          ],
        );
      },
    );
  }
}

// 然后在HomePage或者MyContainer的初始化里调用请求(如果用Stateful的话)
// 或者用方案2的构造函数方式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:43:33