【问题标题】:Flutter FutureBuilder refresh when TextField value changes当 TextField 值更改时 Flutter FutureBuilder 刷新
【发布时间】:2020-05-24 07:23:39
【问题描述】:

_futureData 用于在从_loadPhobias() 函数检索值后用于FutureBuilder

entry_screen.dart

Future _futureData;
final TextEditingController _textEditingController = TextEditingController();

_loadPhobias()函数好像没有问题。

entry_screen.dart

Future<List<String>> _loadPhobias() async =>
    await rootBundle.loadString('assets/phobias.txt').then((phobias) {
    List _listOfAllPhobias = [];
    List<String> _listOfSortedPhobias = [];
    _textEditingController.addListener(() {
      ...
    }); 
    return _listOfSortedPhobias;
});

@override
void initState() {
super.initState();
    _futureData = _loadPhobias();
}

@override
Widget build(BuildContext context) {
    return Scaffold(
    appBar: AppBar(
    title: TextField(
        // When the value is changed, the value returned from the _loadPhobias will also change. So I want the FutureBuilder to be rebuilt.
        onChanged: (text) { setState(() => _futureData =  _loadPhobias()) },
        ),
    ),
    body: FutureBuilder(
        future: _futureData,
        builder: (context, snapshot) {
            return snapshot.hasData
                ? ListView.builder(
                    itemCount: snapshot.data.length,
                    itemBuilder: (context, index) => Column(
                            children: <Widget>[
                                PhobiasCard(sentence: snapshot.data[index]),
                            )
                        ],
                    ))
                    : Center(
                        child: CircularProgressIndicator(),
                    );
                },
            ),
        ),
    );
}

这是我得到的错误:

FlutterError(setState() 回调参数返回一个 Future。

_EntryScreenState#51168 上的 setState() 方法是使用返回 Future 的闭包或方法调用的。也许它被标记为“异步”。

不是在 setState() 调用中执行异步工作,而是先执行工作(不更新小部件状态),然后在 setState() 调用中同步更新状态。)

【问题讨论】:

  • 您好,您能分享一下textEditingController 文本更改侦听器中的内容吗?
  • @juliano for (String i in LineSplitter().convert(phobias)) { _textEditingController.addListener(() { for (String t in _textEditingController.text.split('')) { if (i.split('-').first.toString().contains(t)) { _listOfSortedPhobias.add(i); } } }); } return _listOfSortedPhobias;
  • @juliano texteditingcontroller 返回的数据没有问题可以使用,问题是futurebuilder更新

标签: flutter dart flutter-layout flutter-futurebuilder


【解决方案1】:

在错误信息的第三行可以推断出解决方法:

不是在 setState() 调用中执行异步工作,而是先执行工作(不更新小部件状态),然后在 setState() 调用中同步更新状态。)

因此,这意味着您必须在刷新小部件之前执行该操作。您可以有一个临时变量来保存异步工作的结果并在您的 setState 方法中使用它:

onChanged: (text) {
     setState(() => _futureData =  _loadPhobias())
},

可以写成:

onChanged: (text) async {
    var phobias = _loadPhobias();
    setState(() {
        _futureData = phobias;
    });
},

【讨论】:

  • _futureData 是一个 Future 变量,它不能被分配给一个 List 的恐惧症。你有什么想法让我的futurebuilder刷新吗?我读了其他帖子,但它对我不起作用
  • 如果您在 _loadPhobias() 之前删除了 await 关键字会怎样?就像在更新的答案中一样
【解决方案2】:

首先要注意的是,您提到每次文本发生更改时都希望重建您的应用。为此,您应该改用StreamBuilderFutureBuilder 意味着被消费一次,它就像 JavaScript 中的火灾后遗忘事件或 Promise。

Here 可以很好地比较StreamBuilderFutureBuilder

这就是重构代码以使用StreamBuilder 的方式。

ma​​in.dart

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyAppScreen(),
    );
  }
}

class MyAppScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return MyAppScreenState();
  }
}

class MyAppScreenState extends State<MyAppScreen> {
  StreamController<List<String>> _phobiasStream;

  final TextEditingController _textEditingController = TextEditingController();

  void _loadPhobias() async =>
      await rootBundle.loadString('lib/phobia.txt').then((phobias) {
        List<String> _listOfSortedPhobias = [];
        for (String i in LineSplitter().convert(phobias)) {
          for (String t in _textEditingController.text.split('')) {
            if (i.split('-').first.toString().contains(t)) {
              _listOfSortedPhobias.add(i);
            }
          }
        }
        _phobiasStream.add(_listOfSortedPhobias);
      });

  @override
  void initState() {
    super.initState();
    _phobiasStream = StreamController<List<String>>();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: TextField(
          controller: _textEditingController,
          onChanged: (text) {
            print("Text $text");
            _loadPhobias();
          },
        ),
      ),
      body: StreamBuilder(
        stream: _phobiasStream.stream,
        builder: (context, snapshot) {
          return snapshot.hasData
              ? Container(
                  height: 300,
                  child: ListView.builder(
                    itemCount: snapshot.data.length,
                    itemBuilder: (context, index) {
                      print("Data ${snapshot.data[index]}");
                      return Text(snapshot.data[index]);
                    },
                  ),
                )
              : Center(
                  child: CircularProgressIndicator(),
                );
        },
      ),
    );
  }
}

如上面的代码所示,我在 for 循环中消除了不必要的文本更改回调。

lib/phobia.txt

test1-test2-test3-test4-test5

如果这是预期的情况,请告诉我。

希望这会有所帮助。

【讨论】:

  • 谢谢你。即使我使用未来的构建器解决了它,但我会尝试使用流构建器
猜你喜欢
  • 2020-05-25
  • 1970-01-01
  • 1970-01-01
  • 2021-05-04
  • 2021-12-18
  • 2018-03-22
  • 2021-06-06
  • 1970-01-01
  • 2020-06-18
相关资源
最近更新 更多