如何在Dart/Flutter中克隆Future

jjjwad0x  于 2023-09-28  发布在  Flutter
关注(0)|答案(2)|浏览(121)

我有一个自定义的Flutter小部件,它接收一个future作为其构造函数的参数,并且内部有FutureBuilder
我想添加在连接错误的情况下重新运行此future的功能,但问题是第一次使用后的future已“耗尽”。因此,我需要一些方法来创建一个未来的副本,作为一个参数传递,以使用FutureBuilder内的副本,每次用户按下重新加载按钮。

import 'package:flutter/material.dart';

class CustomFutureBuilder<T> extends StatefulWidget {
  final Future<T> future;

  const CustomFutureBuilder({super.key, required this.future});

  @override
  State<CustomFutureBuilder<T>> createState() => _CustomFutureBuilderState<T>();
}

class _CustomFutureBuilderState<T> extends State<CustomFutureBuilder<T>> {
  late Future<T> _future;

  @override
  void initState() {
    // I need to use initState to initialize _future for the first usage of this widget
    _future = widget.future; // ← here I want to create a future clone and use it instead of original
    super.initState();
  }

  @override
  void didUpdateWidget(covariant CommonFutureBuilder<T> oldWidget) {
    _future = widget.future; // ← and here too
    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _future,
      builder: (context, snapshot) {
        if (snapshot.connectionState != ConnectionState.done) {
          return const LinearProgressIndicator();
        }
        if (snapshot.hasError) {
          debugPrint('Loading error: ${snapshot.error}');
          return Column(
            children: [
              const Text(
                  'Loading error is occurred. Check the internet connection or try again later.'),
              OutlinedButton(
                onPressed: () {
                  setState(() {
                    // ← and maybe here too, I am not sure
                  });
                },
                child: const Text('Reload'),
              ),
            ],
          );
        }

        final data = snapshot.data as T;
        return …
      },
    );
  }
}
nbewdwxp

nbewdwxp1#

你可以尝试用StreamBuilder替换FutureBuilder,因为Future不能监听变量的变化。这是一次性的回应。相反,您需要使用Stream来按用户刷新或事件。
这是您的案例的代码:

late StreamController<T> _conStream;
      @override
      void initState() {
        _conStream= StreamController<T>(); 
        super.initState();
      }
  @override
  void dispose() async {
    _conStream.onCancel;
   await  _conStream.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
          stream: _conStream.stream,
...
  • 刷新功能:
_conStream.add(await Future.delayed(Duration(seconds: 5), () => 'Done') // as example);
8yparm6h

8yparm6h2#

所以我需要一些方法来创造一个未来的副本
解决这个问题的一种方法是注入一个工厂,而不是注入一个Future<T>,生产一个Future<T>
因此,与其将_future传递给构造函数,不如传递一个Function(Future<T>) futureFactory
在你的InitState中,你需要调用它一次:

_future = futureFactory();

然后当有人想再次运行未来时,你做同样的事情:

_future = futureFactory();

你不能重新运行一个未来,但如果你有办法创造那些未来,你就可以去了。

相关问题