TextField 值更改时 Flutter FutureBuilder 刷新
Flutter FutureBuilder refresh when TextField value changes
_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() callback argument returned a Future.
The setState() method on _EntryScreenState#51168 was called with a closure or method that returned a Future. Maybe it is marked as "async".
Instead of performing asynchronous work inside a call to setState(), first execute the work (without updating the widget state), and then synchronously update the state inside a call to setState().)
从错误信息的第三行可以推断出解决方案:
Instead of performing asynchronous work inside a call to setState(), first execute the work (without updating the widget state), and then synchronously update the state inside a call to setState().)
所以这意味着您必须在刷新小部件之前执行该操作。您可以有一个临时变量来保存异步工作的结果,并在您的 setState
方法中使用它:
onChanged: (text) {
setState(() => _futureData = _loadPhobias())
},
可以写成:
onChanged: (text) async {
var phobias = _loadPhobias();
setState(() {
_futureData = phobias;
});
},
首先要注意的是,您提到每次文本发生变化时您都想重建您的应用程序。为此,您应该改用 StreamBuilder
。 FutureBuilder
意味着被消耗一次,就像在 JavaScript.
中的一个 fire and forget 事件或 Promise
很好地比较了 StreamBuilder
与 FutureBuilder
。
这就是您重构代码以使用 StreamBuilder
的方式。
main.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
如果这是预期的情况,请告诉我。
希望对您有所帮助。
_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() callback argument returned a Future.
The setState() method on _EntryScreenState#51168 was called with a closure or method that returned a Future. Maybe it is marked as "async".
Instead of performing asynchronous work inside a call to setState(), first execute the work (without updating the widget state), and then synchronously update the state inside a call to setState().)
从错误信息的第三行可以推断出解决方案:
Instead of performing asynchronous work inside a call to setState(), first execute the work (without updating the widget state), and then synchronously update the state inside a call to setState().)
所以这意味着您必须在刷新小部件之前执行该操作。您可以有一个临时变量来保存异步工作的结果,并在您的 setState
方法中使用它:
onChanged: (text) {
setState(() => _futureData = _loadPhobias())
},
可以写成:
onChanged: (text) async {
var phobias = _loadPhobias();
setState(() {
_futureData = phobias;
});
},
首先要注意的是,您提到每次文本发生变化时您都想重建您的应用程序。为此,您应该改用 StreamBuilder
。 FutureBuilder
意味着被消耗一次,就像在 JavaScript.
StreamBuilder
与 FutureBuilder
。
这就是您重构代码以使用 StreamBuilder
的方式。
main.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
如果这是预期的情况,请告诉我。
希望对您有所帮助。