【问题标题】:StackOverflowError was thrown building FutureBuilder<List<dynamic>>StackOverflowError 在构建 FutureBuilder<List<dynamic>> 时被抛出
【发布时间】:2018-11-13 16:14:07
【问题描述】:

我正在使用 New York Times Best Sellers API,以便我可以获取 Best Sellers 中每个类别的书籍列表。我的代码是这样的:

import "dart:convert";
import "package:flutter/material.dart";
import "package:http/http.dart" as http;
import "package:best_sellers/api.dart";

class BestSellersList extends StatefulWidget {
  final API api;
  final List<dynamic> categories;

  BestSellersList({Key key, @required this.api, @required this.categories}) : super(key: key);

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

class _BestSellersList extends State<BestSellersList> {
  String base, key;
  List<dynamic> categories;
  Future<List<dynamic>> books;

  Future<List<dynamic>> fetchBooks() async {
    try {
      final books = categories.map((category) async {
        final listNameEncoded = category["list_name_encoded"];
        final uri = "$base/$listNameEncoded?api-key=$key";
        final response = await http.get(uri);
        if (response.statusCode == 200) {
          final responseBody = json.decode(response.body);
          final books = responseBody["results"]["books"];
          return books;
        } else { throw Exception(); }
      }).toList();

      if (books.isNotEmpty) {
        return books;
      }
      throw Exception();
    } catch(e) { /**/ }
  }

  void updateBooks() {
    setState(() {
      books = updateBooks();
    });
  }

  @override
  initState() {
    super.initState();
    base = widget.api.base;
    key = widget.api.key;
    categories = widget.categories;
    print("categories.length: ${categories.length}"); // categories.length: 55
    updateBooks();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: books,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return ListView.builder(
            itemCount: snapshot.data.length,
            itemBuilder: (context, index) {
              final displayName = snapshot.data[index]["display_name"];
              return ListTile(title: Text(displayName));
            }
          );
        } else if (snapshot.hasError) {
          return Center(child: Column(
            children: [
              Text(snapshot.error.toString()),
              RaisedButton(
                onPressed: () => updateBooks(),
                child: Text("RETRY"),
              ),
            ],
          ));
        }

        return Center(child: CircularProgressIndicator());
      }
    );
  }
}

在运行我的代码时,我得到了这个堆栈跟踪:

    I/flutter ( 5231): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY
╞═══════════════════════════════════════════════════════════
I/flutter ( 5231): The following StackOverflowError was thrown building FutureBuilder<List<dynamic>>(state:
I/flutter ( 5231): _FutureBuilderState<List<dynamic>>#a3252):
I/flutter ( 5231): Stack Overflow
I/flutter ( 5231): When the exception was thrown, this was the stack:
I/flutter ( 5231): #0      State.mounted (package:flutter/src/widgets/framework.dart:969:3)
I/flutter ( 5231): #1      State.setState.<anonymous closure>
(package:flutter/src/widgets/framework.dart:1113:63)
I/flutter ( 5231): #2      State.setState (package:flutter/src/widgets/framework.dart:1123:6)
I/flutter ( 5231): #3      _BestSellersList.updateBooks (package:best_sellers/best_sellers_list.dart:44:9)
I/flutter ( 5231): #4      _BestSellersList.updateBooks.<anonymous closure>
(package:best_sellers/best_sellers_list.dart:45:19)
I/flutter ( 5231): #5      State.setState (package:flutter/src/widgets/framework.dart:1124:30)
I/flutter ( 5231): #6      _BestSellersList.updateBooks (package:best_sellers/best_sellers_list.dart:44:9)
I/flutter ( 5231): #7      _BestSellersList.updateBooks.<anonymous closure>
(package:best_sellers/best_sellers_list.dart:45:19)
I/flutter ( 5231): #8      State.setState (package:flutter/src/widgets/framework.dart:1124:30)
I/flutter ( 5231): #9      _BestSellersList.updateBooks (package:best_sellers/best_sellers_list.dart:44:9)
I/flutter ( 5231): #10     _BestSellersList.updateBooks.<anonymous closure>
(package:best_sellers/best_sellers_list.dart:45:19)
I/flutter ( 5231): #11     State.setState (package:flutter/src/widgets/framework.dart:1124:30)
I/flutter ( 5231): #12     _BestSellersList.updateBooks (package:best_sellers/best_sellers_list.dart:44:9)
I/flutter ( 5231): #13     _BestSellersList.updateBooks.<anonymous closure>
(package:best_sellers/best_sellers_list.dart:45:19)
                ...................................................
                ...................................................
                ...................................................
    I/flutter ( 5231): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY
╞═══════════════════════════════════════════════════════════
I/flutter ( 5231): The following StackOverflowError was thrown building FutureBuilder<List<dynamic>>(state:
I/flutter ( 5231): _FutureBuilderState<List<dynamic>>#a3252):
I/flutter ( 5231): Stack Overflow
I/flutter ( 5231): When the exception was thrown, this was the stack:
I/flutter ( 5231): #0      State.mounted (package:flutter/src/widgets/framework.dart:969:3)
I/flutter ( 5231): #1      State.setState.<anonymous closure>
(package:flutter/src/widgets/framework.dart:1113:63)
I/flutter ( 5231): #2      State.setState (package:flutter/src/widgets/framework.dart:1123:6)
I/flutter ( 5231): #3      _BestSellersList.updateBooks (package:best_sellers/best_sellers_list.dart:44:9)
I/flutter ( 5231): #4      _BestSellersList.updateBooks.<anonymous closure>
(package:best_sellers/best_sellers_list.dart:45:19)
I/flutter ( 5231): #5      State.setState (package:flutter/src/widgets/framework.dart:1124:30)
I/flutter ( 5231): #6      _BestSellersList.updateBooks (package:best_sellers/best_sellers_list.dart:44:9)
I/flutter ( 5231): #7      _BestSellersList.updateBooks.<anonymous closure>
(package:best_sellers/best_sellers_list.dart:45:19)
I/flutter ( 5231): #8      State.setState (package:flutter/src/widgets/framework.dart:1124:30)
I/flutter ( 5231): #9      _BestSellersList.updateBooks (package:best_sellers/best_sellers_list.dart:44:9)
I/flutter ( 5231): #10     _BestSellersList.updateBooks.<anonymous closure>
(package:best_sellers/best_sellers_list.dart:45:19)
I/flutter ( 5231): #11     State.setState (package:flutter/src/widgets/framework.dart:1124:30)
I/flutter ( 5231): #12     _BestSellersList.updateBooks (package:best_sellers/best_sellers_list.dart:44:9)
I/flutter ( 5231): #13     _BestSellersList.updateBooks.<anonymous closure>
(package:best_sellers/best_sellers_list.dart:45:19)

我了解该错误位于fetchBooks() 方法中,而该方法又由updateBooks() 方法调用,而StackoverflowError 是由过深或无限递归引起的。我正在迭代的 categories 列表有 55 个项目。

【问题讨论】:

  • 你的 updateBooks 自己调用
  • @Developal 我很确定您对我的回答建议的编辑不会起作用,因为fetchBooks() 返回Future&lt;...&gt;

标签: dart flutter future


【解决方案1】:

这是循环:

  void updateBooks() {       // called from vvv
    setState(() {
      books = updateBooks(); // <<<< calls ^^^
    });
  }

你可能想要类似的东西

  void updateBooks() async {     
    var result = await fetchBooks();
    setState(() {
      books = result;
    });
  }

【讨论】:

  • 我认为fetchBooks 的返回值应该直接传递给books 变量,而不是await 解决它,因为books 作为参数传递给@ 987654327@FutureBuilder的参数。
  • 这不是它的工作原理。您需要等待 Future 来获取值,并且在 setState() 中您需要传递值同步,否则 Flutter 将在实际设置值之前重建。根据您建议的更改,您应该会在 IDE 中收到一些警告/错误。
  • 使用这种方法,是否仍需要 FutureBuilder 小部件?
  • 这种方法不需要 FutureBuilder。我没有看到你使用FutureBuilder,这就是为什么我不明白你上面的第一条评论。我宁愿不使用 FutureBuilder 当获取 Future 比简单地调用 getter/方法更多时。
猜你喜欢
  • 2020-02-22
  • 2021-09-08
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
  • 1970-01-01
  • 2020-12-09
  • 2015-10-28
  • 2012-04-29
相关资源
最近更新 更多