我正在学习Flutter。我编写了一个小应用程序,用于从API获取密钥并将其打印在屏幕上。问题是我的getApiKey()方法正在循环。

为什么?我该如何预防呢?

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ChangeNotifierProvider<TenderApiData>(
          builder: (_) => TenderApiData(), child: HomePage()),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(appBar: AppBar(), body: MyContainer());
  }
}

class MyContainer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[MyTestWidget()],
    );
  }
}

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

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

  }

}

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

    );
  }
}

最佳答案

发生这种情况的原因是因为您要在getApiKey函数中通知侦听器,然后getApiKey方法中调用 build。通知侦听器时将调用build方法,看看为什么循环?

无论如何,为防止这种情况,您只需将StatelessWidget转换为StatefulWidget并仅在 getApiKey 中调用State.didChangeDependencies(而不是initState即可,因为您需要访问BuildContext):

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

class _MyTestWidgetState extends State<MyTestWidget> {
  bool apiKeyLoaded;

  @override
  void initState() {
    apiKeyLoaded = false;
    super.initState();
  }

  @override
  void didChangeDependencies() {
    if (!apiKeyLoaded) {
      Provider.of<TenderApiData>(context).getApiKey();
      apiKeyLoaded = true;
    }
    super.didChangeDependencies();
  }


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

    );
  }
}

08-17 18:11