我正在尝试通过创建一个绘制随机路径的应用程序来掌握Flutter(它会在完成之前变得更高级!)。用户可以更改路径中的图块数,并且此值将保存在“共享首选项”中。如果他们不更改切片数,则将其设置为默认值15.5。
我遇到的问题是,它试图在完成读取“共享首选项”之前绘制路径,并且由于未设置图块数量而崩溃。我可以设置默认值,但是它会先绘制默认值,然后使用其他数量的图块重新绘制,这是我不希望的-我希望它首先绘制用户设置的图块数量,并且仅使用如果用户尚未设置号码,则为默认值。
我认为我需要使用FutureBuilder
,但是我在网上找不到很多可以帮助到我的地方。这是我到目前为止的内容(这是main.dart):
void main() {
runApp(MaterialApp(
title: "Path Maker",
home: PathMaker(),
));
}
class PathMaker extends StatefulWidget {
int numTiles;
PathMaker({
Key key,
this.numTiles
}): super(key: key);
@override
_PathMakerState createState() => new _PathMakerState();
}
class _PathMakerState extends State<PathMaker> {
_PathMakerState();
@override
void initState() {
super.initState();
getPreferences();
}
@override
void dispose() {
super.dispose();
}
void getPreferences() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
// Get timing variables
Set<String> keys = prefs.getKeys();
if(keys.contains('numTiles')) {
numTiles = prefs.getInt('numTiles');
}else {
numTiles = 15.5;
}
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Path Maker',
theme: new ThemeData(
primarySwatch: Colors.green,
),
home: new Path(widget.numTiles),
);
}
}
(path.dart是定义Path
类的另一个文件-我认为它不相关,但是可以在需要时将其发布)。因此,基本上,我希望它仅在getPreferences
完成后才调用build。我该如何处理?我是完全采取了错误的方法吗?
答案 0 :(得分:1)
使用FutureBuilder
使您处在正确的轨道上。
它有两个参数,future
期望一些Future
,这是一个延迟的计算或一个潜在值。在您的情况下,这是从Future<SharedPreferences>
返回的SharedPreferences.getInstance()
。
然后FutureBuilder
会期望一个builder
。将使用上下文和与您的未来类型相对应的AsyncSnapshot
来调用构建器。 AsyncSnapshot
代表与异步计算的最新交互-在您的情况下,是检索共享首选项实例。 AsyncSnapshot.connectionState
允许我们根据Future
的状态决定要渲染的窗口小部件。 FutureBuilder
example详细介绍了不同的状态,现在我们只看ConnectionState.done
。
在done
状态下,快照包含一个错误-我们将不在此处处理-或data
,即您的异步函数调用的返回值。
以您的示例为例,我们可以创建一个FutureBuilder<SharedPreferences>
。通用类型指示将来将返回的类型。我们将共享首选项getInstance
方法中的future分配给future参数,并分配一个预期上下文和异步快照的构建器关闭。
使用此代码,您的代码应如下所示:
class _PathMakerState extends State<PathMaker> {
_PathMakerState();
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
void setTiles(SharedPreferences prefs) {
// Get timing variables
Set<String> keys = prefs.getKeys();
if(keys.contains('numTiles')) {
widget.numTiles = prefs.getDouble('numTiles');
}else {
widget.numTiles = 15.5;
}
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Path Maker',
theme: new ThemeData(
primarySwatch: Colors.green,
),
home: FutureBuilder<SharedPreferences>(
future: SharedPreferences.getInstance(),
builder: (BuildContext context, AsyncSnapshot<SharedPreferences> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
// get the tile number from the shared preference instance
// stored in snapshot.data
setTiles(snapshot.data);
return Path(widget.numTiles);
default:
return Text("Loading...");
}
}
),
);
}
}