It is entirely possible that StreamBuilder.builder will be called while the Stream has no data, hasn't connected to the Stream yet or the value is null.
It is up to you to make sure that you handle all these cases.
To make sure that the initial value is never null, you can set inialData.
Future<String> someFutureString = Future.value('initial data seeded');
new StreamBuilder<String>(
initialData: await someFutureString,
builder: (ctx, snapshot) { /* ... */ }
);
This is bad practice though. It is better to build such builder that consider the state of the snapshot it works with. Building the widget tree should be quick. Imagine having to wait 3 seconds to the initialData. Your widget tree building will be blocked by at the first await.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
wrapInMaterialApp(Widget widget) => MaterialApp(
home: widget,
);
main() {
testWidgets('can await initial data', (WidgetTester tester) async {
final initialData = Future<String>.value('initial value');
final stream = Stream.fromIterable(['first']);
final sb = StreamBuilder<String>(
initialData: await initialData,
builder: (ctx, snapshot) {
return Text('${snapshot.data}');
},
);
await tester.pumpWidget(wrapInMaterialApp(sb));
// Verify that initial data is present
expect(find.text('initial value'), findsOneWidget);
});
testWidgets('can return subtree if there is data', (WidgetTester tester) async {
final stream = Stream.fromIterable(['first']);
final sb = StreamBuilder<String>(
stream: stream,
builder: (ctx, snapshot) {
if (snapshot.hasData) {
return Text('${snapshot.data}');
} else
return Container();
},
);
var wrappedWidget = wrapInMaterialApp(sb);
await tester.pumpWidget(wrappedWidget);
expect(find.byType(Container), findsOneWidget);
expect(find.text('first'), findsNothing);
await tester.pump();
expect(find.byType(Container), findsNothing);
expect(find.text('first'), findsOneWidget);
});
}
Other things that can help you determine what Widget your builder should return is ConnectionState, accessible through snapshot.connectionState.
Cheers!
StreamBuilder- see dart.dev/tutorials/language/streams and dart.dev/articles/libraries/creating-streams for more info