语境

我遇到了一个FutureBuilder in Ffltter的问题,在每次小部件重建时,它都会重新创建Future,导致我的应用程序出现意外行为.

具体地说,我有一个获取随机数的FutureBuilder,但每次我触发重新构建(例如,通过按下按钮更新计数器)时,它都会生成一个新的随机数,而不是使用最初获取的值.

问题

当我试图通过按下按钮来更新计数器时,出现了这个问题.每按一次不仅更新计数器,also还会重新生成由FutureBuilder显示的随机数.我希望保留第一个生成的随机数,除非显式刷新.

以下是问题的视频表示:

enter image description here

代码

以下是演示该问题的完整的可运行程序:

import 'package:flutter/material.dart';

import 'dart:math'; // For generating random numbers

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(Build语境 context) {
    return const MaterialApp(
      title: 'FutureBuilder Example',
      home: FutureBuilderExample(),
    );
  }
}

class FutureBuilderExample extends StatefulWidget {
  const FutureBuilderExample({super.key});

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

class _FutureBuilderExampleState extends State<FutureBuilderExample> {
  int counter = 0;

  Future<int> fetchRandomNumber() async {
    await Future.delayed(const Duration(milliseconds: 500));
    return Random().nextInt(100);
  }

  @override
  Widget build(Build语境 context) {
    return Scaffold(
      appBar: AppBar(title: const Text('FutureBuilder with Random Number')),
      body: Column(
        children: [
          Text('Counter: $counter'),
          FutureBuilder<int>(
            future:
                fetchRandomNumber(), // Future is recreated here on every build
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return const Center(child: CircularProgressIndicator());
              } else if (snapshot.hasError) {
                return Center(child: Text('Error: ${snapshot.error}'));
              } else {
                return Center(child: Text('Random Number: ${snapshot.data}'));
              }
            },
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            counter++; // Triggering rebuild
          });
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

问题

我正在寻找一种方法,防止FutureBuilder人在每次重建时重新创造future .我怎样才能做到这一点呢?

此问题旨在作为解决FutureBuilderStreamBuilder中类似问题的规范参考.

推荐答案

Explanation

你在Flutter 中遇到的问题是很常见的.

这里要理解的关键点是,应该为FutureBuilder提供future,该future不会在每次构建时更改,除非您特别希望重新执行异步操作.

当你直接在FutureBuilder中创造future 时,它会在每一次构建(例如每setState次)上重新创建,这就是为什么你会观察到每次按下按钮时随机数字的变化.

Solution: Using initState to Initialize the Future

解决方案是初始化您的future once,并在FutureBuilder内使用这个稳定的引用.这通常是通过在StatefulWidgetinitState方法中定义future 来实现的.

class _FutureBuilderExampleState extends State<FutureBuilderExample> {
  int counter = 0;
  late Future<int> randomNumberFuture; // Define the future here, use the `late` keyword

  @override
  void initState() {
    super.initState();
    randomNumberFuture = fetchRandomNumber(); // Initialize the future in initState
  }

然后,在你的FutureBuilder分中:

 FutureBuilder<int>(
    future: randomNumberFuture, // Use the above-initialized future here
    builder: (context, snapshot) {

Code example

以下是使用initState的完整重构代码片段:

import 'dart:math';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'FutureBuilder Example',
      home: FutureBuilderExample(),
    );
  }
}

class FutureBuilderExample extends StatefulWidget {
  const FutureBuilderExample({super.key});

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

class _FutureBuilderExampleState extends State<FutureBuilderExample> {
  int counter = 0;
  //1. Define the future here
  late Future<int> randomNumberFuture; // Define the future here

  @override
  void initState() {
    super.initState();
    //2. Initialize the future here
    randomNumberFuture =
        fetchRandomNumber(); // Initialize the future in initState
  }

  Future<int> fetchRandomNumber() async {
    await Future.delayed(const Duration(milliseconds: 500));
    return Random().nextInt(100);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('FutureBuilder with Random Number')),
      body: Center(
        child: Column(
          children: [
            Text('Counter: $counter', style: TextStyle(fontSize: 24)),
            FutureBuilder<int>(
              // 3. Use the initialized future here
              future: randomNumberFuture, // Use the initialized future here
              builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return const CircularProgressIndicator();
                } else if (snapshot.hasError) {
                  return Text('Error: ${snapshot.error}');
                } else {
                  return Text('Random Number: ${snapshot.data}',
                      style: TextStyle(fontSize: 24));
                }
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            counter++; // Triggering rebuild, but not affecting the future
          });
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

正如你现在看到的,只有计数器在更新,not是随机数:

enter image description here

Going further

  • 我建议你观看关于如何以正确的方式创建FutureBuilderthis YouTube视频.他在视频中1点55分解释了你的问题.

  • 兰德尔·施瓦茨关于这个问题和如何解决它的Another YouTube video篇文章

  • This堆栈溢出应答.

Flutter相关问答推荐

在Flutter 动中绘制ECG图

功能不起作用的Flutter 块复制

在Android Studio的新用户界面中未找到热重新加载

点击表情符号按钮后,Flutter 文本域文本编辑控制器将文本恢复为原始值

如何使用Dio/Ffltter(前端)和amp;Go(后端)向API发送正确的请求

无法在我的Flutter 应用程序中使用GoRouter测试导航

为什么在setState之后Ffltter Pageview重置为第0页

将记录/元组用作SplayTreeMap中的键

如何在Flutter 中使用滚动展开窗口小部件

使用现有Map方法对子类克隆方法的逻辑进行Dart标准化

TextField 中的富文本并获取 RenderParagraph

了解多Provider 和流

尽管海拔设置为 0,如何删除 appBar 下的下划线

在Flutter中为容器实现线性渐变背景动画

Flutter列顶部和底部出现不必要的边距问题

Flutter 自定义对齐

Flutter 动画页面计数器文本

为什么 Flutter riverpod 直接分配不起作用但方法可以

如何在手势检测器中获得涟漪效应

我想在数组中添加项目