【问题标题】:Flutter FutureBuilder resolving multiple times without build() being calledFlutter FutureBuilder 在没有调用 build() 的情况下多次解析
【发布时间】:2022-11-24 18:17:07
【问题描述】:

我的小部件多次运行其 FutureBuilder 代码时遇到问题,Future 已解决。与 SO 上关于此的其他问题不同,我的 build() 方法没有被多次调用。

我的未来在build()之外被initState()调用 - 它也被包裹在AsyncMemoizer中。

相关代码:

class _HomeScreenState extends State<HomeScreen> {
  late final Future myFuture;
  final AsyncMemoizer _memoizer = AsyncMemoizer();

  @override
  void initState() {
    super.initState();

    /// provider package
    final homeService = context.read<HomeService>();
    myFuture = _memoizer.runOnce(homeService.getMyData);
  }

  @override
  Widget build(BuildContext context) {
    print("[HOME] BUILDING OUR HOME SCREEN");

    return FutureBuilder(
      future: myFuture,
      builder: ((context, snapshot) {
        print("[HOME] BUILDER CALLED WITH SNAPSHOT: $snapshot - connection state: ${snapshot.connectionState}");

当我运行代码并触发错误时(显示的软键盘设法在 50% 的时间内触发它,但并非所有时间),我的日志是:

I/flutter (29283): [HOME] BUILDING OUR HOME SCREEN
I/flutter (29283): [HOME] BUILDER CALLED WITH SNAPSHOT: AsyncSnapshot<dynamic>(ConnectionState.waiting, null, null, null) - connection state: ConnectionState.waiting
I/flutter (29283): [HOME] BUILDER CALLED WITH SNAPSHOT: AsyncSnapshot<dynamic>(ConnectionState.done, Instance of 'HomeData', null, null) - connection state: ConnectionState.done
...
/// bug triggered
...
I/flutter (29283): [HOME] BUILDER CALLED WITH SNAPSHOT: AsyncSnapshot<dynamic>(ConnectionState.done, Instance of 'HomeData', null, null) - connection state: ConnectionState.done

ConnectionState.waiting 的初始调用是正常的,然后我们使用ConnectionState.done 获得第一个构建。

触发错误后,我得到了另一个FutureBuilder resolve没有build() 方法被调用。

我在这里错过了什么吗?

用完整的例子编辑

这显示了有问题的错误 - 如果您单击进入和退出 TextField,将再次调用 FutureBuilder

这似乎与键盘的隐藏方式有关。如果我使用FocusScopeNode方法,它会重建,而如果我使用FocusManager,它不会,所以我不确定这是否是一个错误。

import 'package:flutter/material.dart';

void main() async {
  runApp(const TestApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Testapp',
      home: Scaffold(
        body: TestAppHomeScreen(),
      ),
    );
  }
}

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

  @override
  State<TestAppHomeScreen> createState() => _TestAppHomeScreenState();
}

class _TestAppHomeScreenState extends State<TestAppHomeScreen> {
  late final Future myFuture;

  @override
  void initState() {
    super.initState();

    myFuture = Future.delayed(const Duration(milliseconds: 500), () => true);

    print("[HOME] HOME SCREEN INIT STATE CALLED: $hashCode");
  }

  @override
  Widget build(BuildContext context) {
    print("[HOME] HOME SCREEN BUILD CALLED: $hashCode");
    return FutureBuilder(
      future: myFuture,
      builder: (context, snapshot) {
        print("[HOME] HOME SCREEN FUTURE BUILDER CALLED WITH STATE ${snapshot.connectionState}: $hashCode");
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Scaffold(
            body: Center(
              child: CircularProgressIndicator(),
            ),
          );
        }

        return GestureDetector(
          onTapUp: (details) {
            // hide the keyboard if it's showing
            FocusScopeNode currentFocus = FocusScope.of(context);
            if (!currentFocus.hasPrimaryFocus) {
              currentFocus.unfocus();
            }
            // FocusManager.instance.primaryFocus?.unfocus();
          },
          child: const Scaffold(
            body: Center(
              child: Padding(
                padding: EdgeInsets.symmetric(horizontal: 32.0),
                child: TextField(),
              ),
            ),
          ),
        );
      },
    );
  }
}

【问题讨论】:

  • 我无法重现这个,你能更具体地说明你所指的这个“错误”吗?你能发布一个完整的可重现的例子吗?
  • 我添加了一个可重现的例子@venir

标签: flutter


【解决方案1】:

请试试这个解决方案/// provider package super.initState();

你的代码将是这样的

  @override
  void initState() {
    /// provider package
    final homeService = context.read<HomeService>();
    myFuture = _memoizer.runOnce(homeService.getMyData);
    super.initState();
  }

请尝试后告诉我结果

【讨论】:

  • 不幸的是,这并没有改变
  • 你有任何setState吗
  • 我用一个可重现的例子更新了这个问题——它似乎与如何从键盘上移除焦点有关
猜你喜欢
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 2015-02-26
  • 1970-01-01
  • 2021-12-19
相关资源
最近更新 更多