Is StreamBuilder always called twice? Once for initial data and then once for the input stream?
Initializing the following StreamBuilder shows that the build method is called twice. The second call is 0.4 seconds after the first one.
Stream: Build 1566239814897
Stream: Build 1566239815284
import 'dart:async';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:nocd/utils/bloc_provider.dart';
void main() =>
runApp(BlocProvider<MyAppBloc>(bloc: MyAppBloc(), child: MyApp()));
class MyAppBloc extends BlocBase {
String _page = window.defaultRouteName ?? "";
/// Stream for [getPage].
StreamController<String> pageController = StreamController<String>();
/// Observable navigation route value.
Stream get getPage => pageController.stream;
MyAppBloc() {}
@override
void dispose() {
pageController.close();
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final MyAppBloc myAppBloc = BlocProvider.of<MyAppBloc>(context);
return StreamBuilder(
stream: myAppBloc.getPage,
initialData: "Build",
builder: (context, snapshot) {
print("Stream: " +
snapshot.data +
DateTime.now().millisecondsSinceEpoch.toString());
return Container();
},
);
}
}
Why is the StreamBuilder called twice?
StreamBuilder makes two build calls when initialized, once for the initial data and a second time for the stream data.
Streams do not guarantee that they will send data right away so an initial data value is required. Passing null
to initialData
throws an InvalidArgument exception.
StreamBuilders will always build twice even when the stream passed is null.
Update:
A detailed technical explanation of why StreamBuilders build multiple times even when an initalData
is provided can be found in this Flutter issue thread: https://github.com/flutter/flutter/issues/16465
It's not possible for a broadcast stream to have an initial state. Either you were subscribed when the data was added or you missed it. In an async single-subscription stream, any listen calls added won't be invoked until either the next microtask or next event loop (can't remember, may depend), but at any rate there is no way to get the data out the stream on the current frame. - jonahwilliams