Flutter StreamBuilder vs FutureBuilder

StreamBuilderFutureBuilder的主要区别是什么。

  • 使用什么和什么时候使用?

  • 它们打算执行哪些任务?

  • 它们如何监听动态列表中的更改?

54471 次浏览

StreamBuilderFutureBuilder具有相同的行为: 它们监听各自对象上的更改。并在接到通知时触发新的构建 一个新的价值。

所以最后,他们的不同之处在于他们听到的对象是如何工作的。

Future类似于 JS 中的 Promise或 c # 中的 Task。它们是异步请求的表示形式。Futures只有一个响应。Future的一个常见用法是处理 HTTP 调用。你可以在 Future上听到的是它的状态。无论是完成了,成功完成了,还是出了差错。但仅此而已。

另一方面,Stream与 JS 中的异步 Iterator相似。这可以被同化为一个随时间变化的值。它通常是 Web 套接字或事件(如点击)的表示。通过收听 Stream,您将得到每个新值,也如果 Stream有一个错误或完成。

它们如何监听动态列表中的更改?

Future无法监听变量更改。这是一次性响应。相反,您需要使用 Stream

FutureBuilder用于一次性响应,如从相机获取图像、从本地平台获取一次性数据(如获取设备电池)、获取文件引用、发出 http 请求等。

另一方面,StreamBuilder用于不止一次地获取某些数据,如收听位置更新、播放音乐、秒表等。


下面是提到这两种情况的完整例子。

FutureBuilder解决一个平方值并在5秒钟后返回结果,直到我们向用户显示进度指示器。

StreamBuilder显示一个秒表,每秒钟将 _count值递增1。

void main() => runApp(MaterialApp(home: HomePage()));


class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}


class _HomePageState extends State<HomePage> {
int _count = 0; // used by StreamBuilder


@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildFutureBuilder(),
SizedBox(height: 24),
_buildStreamBuilder(),
],
),
);
}


// constructing FutureBuilder
Widget _buildFutureBuilder() {
return Center(
child: FutureBuilder<int>(
future: _calculateSquare(10),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done)
return Text("Square = ${snapshot.data}");


return CircularProgressIndicator();
},
),
);
}


// used by FutureBuilder
Future<int> _calculateSquare(int num) async {
await Future.delayed(Duration(seconds: 5));
return num * num;
}


// constructing StreamBuilder
Widget _buildStreamBuilder() {
return Center(
child: StreamBuilder<int>(
stream: _stopwatch(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active)
return Text("Stopwatch = ${snapshot.data}");


return CircularProgressIndicator();
},
),
);
}


// used by StreamBuilder
Stream<int> _stopwatch() async* {
while (true) {
await Future.delayed(Duration(seconds: 1));
yield _count++;
}
}
}

我发现有时现实世界的类比对于解释/记忆概念很有效。这里有一个-它不是完美的,但它帮助我。

想象一下你在一家现代的寿司店里,你有一条带子绕着房间转,上面有寿司船。你只要坐下来,等一个人走过,抓起来吃。但是他们也允许你命令执行。

未来就像一个标记,上面有一个数字,当你点外卖时,他们会给你这个数字; 你提出了请求,但是结果还没有准备好,但是你有一个占位符。当结果准备好了,你会得到一个回复(外卖柜台上方的数字显示板显示你的号码,或者他们喊出来)——你现在可以进去拿你的食物(结果)外卖。

溪流就像那个带着小寿司碗的腰带。坐在那张桌子旁,你已经“订阅”了这条流。你不知道下一艘寿司船什么时候到达——但是当厨师(消息来源)把它放在流(带)中时,订阅者就会收到它。需要注意的重要一点是,它们是异步到达的(你不知道下一条船/信息什么时候到达) ,但它们会按顺序到达(也就是说,如果厨师把三种类型的寿司按某种顺序放在腰带上——你会看到它们以同样的顺序从你身边经过)

从编码的角度来看—— Futures 和 Streams 都可以帮助您处理异步(在这种情况下,事情不会立即发生,而且您不知道 什么时候,在您发出请求之后您将得到一个结果)。

不同之处在于 Futures 是关于一次性请求/响应(我问,有一个延迟,我得到一个通知,说我的 Future 已经准备好收集了,然后我就完成了!)而 Streams 是对单个请求的一系列连续响应(我问,有一个延迟,然后我继续得到响应,直到流干涸或者我决定关闭它并离开)。

希望能帮上忙。

FutureBuilder StreamBuilder的行为类似: 它们监听各自对象中的更改。为了响应更改值通知,将触发一个新的构建。

最终,区别在于它们如何监听异步调用。

未来建设者

对此只有一种反应。期货通常用于 http 呼叫。Future 可以用来监听状态,例如,当它完成获取数据或出现错误时。

例如链接 给你

StreamBuilder

与流相反,流是迭代器,可以吸收不同的值,这些值将随着时间的推移而变化。Stream 将返回每个新值以及错误消息或成功消息(如果有的话)。

例如链接 给你

结论

以下数据可能有助于你更好地理解上述内容:

如果您的用例只是获取数据并显示它,比如来自 API 的类的总课程数。然后你就可以使用 FutureBuilder 了。 如果在你使用应用程序的时候,数据每秒或每分钟更新一次,比如在博客中即将发表的文章,或者在博客上增加评论,或者在博客上增加喜欢,会怎么样呢。它在一定时间间隔内异步更新,在这种情况下 StreamBuilder 是最佳选择。 根据用例,您可以决定使用哪一个。

这里有一个完整的例子提到了这两种情况。 FutureBuilder 解决一个平方值并在5秒后返回结果,直到我们向用户显示一个进度指示器。

StreamBuilder 显示一个秒表,其中 _ count 值每秒递增1。

void main() => runApp(MaterialApp(home: HomePage()));


class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}


class _HomePageState extends State<HomePage> {
int _count = 0; // used by StreamBuilder


@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildFutureBuilder(),
SizedBox(height: 24),
_buildStreamBuilder(),
],
),
);
}


// constructing FutureBuilder
Widget _buildFutureBuilder() {
return Center(
child: FutureBuilder<int>(
future: _calculateSquare(10),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done)
return Text("Square = ${snapshot.data}");


return CircularProgressIndicator();
},
),
);
}


// used by FutureBuilder
Future<int> _calculateSquare(int num) async {
await Future.delayed(Duration(seconds: 5));
return num * num;
}


// constructing StreamBuilder
Widget _buildStreamBuilder() {
return Center(
child: StreamBuilder<int>(
stream: _stopwatch(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active)
return Text("Stopwatch = ${snapshot.data}");


return CircularProgressIndicator();
},
),
);
}


// used by StreamBuilder
Stream<int> _stopwatch() async* {
while (true) {
await Future.delayed(Duration(seconds: 1));
yield _count++;
}
}
}