如何防止Build方法循环?

时间:2019-07-30 08:59:17

标签: flutter dart

我正在学习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"))
      ],

    );
  }
}

1 个答案:

答案 0 :(得分:4)

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

无论如何,要防止发生这种情况,您只需将StatelessWidget转换为StatefulWidget并仅在State.didChangeDependencies中调用getApiKey(而不是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"))
      ],

    );
  }
}