为什么在ListView Flutter中滚动时会调用FutureBuilder Multiple?

时间:2019-04-27 04:52:35

标签: flutter

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

您可以在这里https://youtu.be/OKjiMOSJmYA

看到我如何重现此问题。
  @PersistenceContext
  private EntityManager em;

  Query q = em.createNativeQuery("select * from <tablename>");
  List<Object[]> results = q.getResultList();

现在像这样在控制台中

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(),
          )
        ],
      ),
    );
  }
}

2 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

在文档中指出,如果您将来进行更改,则build方法将始终被调用两次:

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.

查看文档:{​​{3}}

您的代码应通过保持呼叫计数器和仅在第二次呼叫中更新列表之类的方法进行修改。