【问题标题】:Why FutureBuilder multiple called when scrolling in ListView Flutter?为什么在 ListView Flutter 中滚动时会调用 FutureBuilder 多次?
【发布时间】:2019-09-16 13:01:43
【问题描述】:

我有一个带有子 FutureBuilder 和 ListView.Builder 的 ListView。在 FutureBuilder 中,我有 ListView。现在的问题是,当我滚动 ListView 父级时,为什么 FutureBuilder 会再次重建?

你可以在这里看到我是如何重现这个问题的https://youtu.be/OKjiMOSJmYA

import 'package:flutter/material.dart';

class DebugScreen extends StatefulWidget {
  @override
  _DebugScreenState createState() => _DebugScreenState();
}

class _DebugScreenState extends State<DebugScreen> {
  List<int> numbers = [1, 2, 3, 4, 5, 6, 7];
  var futureData;
  var futureBuilderHelloWorld;

  Future<List<int>> getFutureData() async {
    print("getFutureData");
    var numbers = [
      1,
      2,
      3,
      4,
      5,
      6,
      7,
      8,
      9,
      10,
      11,
      12,
      13,
      14,
      15,
      16,
      17,
      18,
      19,
      20,
      21,
      22,
      23,
      24,
      25,
      26,
      27,
      28,
      29,
      30,
    ];
    await Future.delayed(Duration(seconds: 3));
    return await numbers;
  }

  @override
  void initState() {
    futureData = getFutureData();
    futureBuilderHelloWorld = FutureBuilder(
      future: futureData,
      builder: (context, AsyncSnapshot<List<int>> snapshot) {
        print("future builder"); // why this is called when scrolling
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
            return Center(
              child: CircularProgressIndicator(),
            );
          default:
            if (snapshot.hasError) {
              return Text("Error: " + snapshot.error.toString());
            } else {
              var numbers = snapshot.data;
              return Container(
                height: 190.0,
                child: ListView.builder(
                  shrinkWrap: true,
                  itemCount: numbers.length,
                  itemBuilder: (context, index) {
                    return Padding(
                      padding: const EdgeInsets.all(16.0),
                      child: Text("Hello world ${numbers[index]}"),
                    );
                  },
                ),
              );
            }
        }
      },
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Debug Mode"),
      ),
      body: ListView(
        children: <Widget>[
          futureBuilderHelloWorld,
          ListView(
            shrinkWrap: true,
            physics: ClampingScrollPhysics(),
            children: List.generate(100, (index) {
              return Text("Flutter $index");
            }).toList(),
          )
        ],
      ),
    );
  }
}

现在在控制台中就像这样

I/flutter (18634): future builder
I/flutter (18634): future builder
I/flutter (18634): future builder
I/flutter (18634): future builder

【问题讨论】:

  • 面临同样的问题。你能找到它的根本原因吗?
  • 同样的问题,有解决办法吗?

标签: flutter


【解决方案1】:

在文档中指出,如果您将来发生变化,构建方法将始终被调用两次:

If the old future has already completed successfully with data as above, changing configuration to a new future results in snapshot pairs of the form:

new AsyncSnapshot<String>.withData(ConnectionState.none, 'data of first future')
new AsyncSnapshot<String>.withData(ConnectionState.waiting, 'data of second future')
In general, the latter will be produced only when the new future is non-null, and the former only when the old future is non-null.

查看文档:https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

您的代码应该通过保持呼叫计数器和仅在第二次呼叫中更新列表等方式来适应这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 2023-04-07
    • 2019-08-10
    • 1970-01-01
    • 2010-10-31
    相关资源
    最近更新 更多