Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
c3fab029
Commit
c3fab029
authored
Jan 06, 2018
by
Brian Egan
Committed by
Mikkel Nygaard Ravn
Jan 06, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Idea: Provide initial data to the StreamBuilder (#13820)
parent
c669c62e
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
104 additions
and
9 deletions
+104
-9
async.dart
packages/flutter/lib/src/widgets/async.dart
+31
-9
async_test.dart
packages/flutter/test/widgets/async_test.dart
+73
-0
No files found.
packages/flutter/lib/src/widgets/async.dart
View file @
c3fab029
...
...
@@ -267,13 +267,13 @@ typedef Widget AsyncWidgetBuilder<T>(BuildContext context, AsyncSnapshot<T> snap
/// a [Stream].
///
/// Widget rebuilding is scheduled by each interaction, using [State.setState],
/// but is otherwise decoupled from the timing of the stream. The [build
] method
/// but is otherwise decoupled from the timing of the stream. The [build
er]
/// is called at the discretion of the Flutter pipeline, and will thus receive a
/// timing-dependent sub-sequence of the snapshots that represent the
/// interaction with the stream.
///
/// As an example, when interacting with a stream producing the integers
/// 0 through 9, the [build
] method
may be called with any ordered sub-sequence
/// 0 through 9, the [build
er]
may be called with any ordered sub-sequence
/// of the following snapshots that includes the last one (the one with
/// ConnectionState.done):
///
...
...
@@ -284,8 +284,9 @@ typedef Widget AsyncWidgetBuilder<T>(BuildContext context, AsyncSnapshot<T> snap
/// * `new AsyncSnapshot<int>.withData(ConnectionState.active, 9)`
/// * `new AsyncSnapshot<int>.withData(ConnectionState.done, 9)`
///
/// The actual sequence of invocations of [build] depends on the relative timing
/// of events produced by the stream and the build rate of the Flutter pipeline.
/// The actual sequence of invocations of the [builder] depends on the relative
/// timing of events produced by the stream and the build rate of the Flutter
/// pipeline.
///
/// Changing the [StreamBuilder] configuration to another stream during event
/// generation introduces snapshot pairs of the form
...
...
@@ -303,6 +304,11 @@ typedef Widget AsyncWidgetBuilder<T>(BuildContext context, AsyncSnapshot<T> snap
/// The data and error fields of snapshots produced are only changed when the
/// state is `ConnectionState.active`.
///
/// The initial snapshot data can be controlled by specifying [initialData].
/// You would use this facility to ensure that if the [builder] is invoked
/// before the first event arrives on the stream, the snapshot carries data of
/// your choice rather than the default null value.
///
/// See also:
///
/// * [StreamBuilderBase], which supports widget building based on a computation
...
...
@@ -333,19 +339,25 @@ typedef Widget AsyncWidgetBuilder<T>(BuildContext context, AsyncSnapshot<T> snap
class
StreamBuilder
<
T
>
extends
StreamBuilderBase
<
T
,
AsyncSnapshot
<
T
>>
{
/// Creates a new [StreamBuilder] that builds itself based on the latest
/// snapshot of interaction with the specified [stream] and whose build
/// strategy is given by [builder].
/// strategy is given by [builder]. The [initialData] is used to create the
/// initial snapshot. It is null by default.
const
StreamBuilder
({
Key
key
,
this
.
initialData
,
Stream
<
T
>
stream
,
@required
this
.
builder
})
:
assert
(
builder
!=
null
),
})
:
assert
(
builder
!=
null
),
super
(
key:
key
,
stream:
stream
);
/// The build strategy currently used by this builder. Cannot be null.
final
AsyncWidgetBuilder
<
T
>
builder
;
/// The data that will be used to create the initial snapshot. Null by default.
final
T
initialData
;
@override
AsyncSnapshot
<
T
>
initial
()
=>
new
AsyncSnapshot
<
T
>.
nothing
();
// ignore: prefer_const_constructors
AsyncSnapshot
<
T
>
initial
()
=>
new
AsyncSnapshot
<
T
>.
withData
(
ConnectionState
.
none
,
initialData
);
@override
AsyncSnapshot
<
T
>
afterConnected
(
AsyncSnapshot
<
T
>
current
)
=>
current
.
inState
(
ConnectionState
.
waiting
);
...
...
@@ -391,6 +403,11 @@ class StreamBuilder<T> extends StreamBuilderBase<T, AsyncSnapshot<T>> {
/// * `new AsyncSnapshot<String>.withData(ConnectionState.waiting, null)`
/// * `new AsyncSnapshot<String>.withError(ConnectionState.done, 'some error')`
///
/// The initial snapshot data can be controlled by specifying [initialData]. You
/// would use this facility to ensure that if the [builder] is invoked before
/// the future completes, the snapshot carries data of your choice rather than
/// the default null value.
///
/// The data and error fields of the snapshot change only as the connection
/// state field transitions from `waiting` to `done`, and they will be retained
/// when changing the [FutureBuilder] configuration to another future. If the
...
...
@@ -437,6 +454,7 @@ class FutureBuilder<T> extends StatefulWidget {
const
FutureBuilder
({
Key
key
,
this
.
future
,
this
.
initialData
,
@required
this
.
builder
})
:
assert
(
builder
!=
null
),
super
(
key:
key
);
...
...
@@ -448,6 +466,9 @@ class FutureBuilder<T> extends StatefulWidget {
/// The build strategy currently used by this builder. Cannot be null.
final
AsyncWidgetBuilder
<
T
>
builder
;
/// The data that will be used to create the initial snapshot. Null by default.
final
T
initialData
;
@override
State
<
FutureBuilder
<
T
>>
createState
()
=>
new
_FutureBuilderState
<
T
>();
}
...
...
@@ -458,11 +479,12 @@ class _FutureBuilderState<T> extends State<FutureBuilder<T>> {
/// calling setState from stale callbacks, e.g. after disposal of this state,
/// or after widget reconfiguration to a new Future.
Object
_activeCallbackIdentity
;
AsyncSnapshot
<
T
>
_snapshot
=
new
AsyncSnapshot
<
T
>.
nothing
();
// ignore: prefer_const_constructors
AsyncSnapshot
<
T
>
_snapshot
;
@override
void
initState
()
{
super
.
initState
();
_snapshot
=
new
AsyncSnapshot
<
T
>.
withData
(
ConnectionState
.
none
,
widget
.
initialData
);
_subscribe
();
}
...
...
packages/flutter/test/widgets/async_test.dart
View file @
c3fab029
...
...
@@ -118,6 +118,34 @@ void main() {
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.done, null, bad)'
),
findsOneWidget
);
});
testWidgets
(
'runs the builder using given initial data'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
new
GlobalKey
();
await
tester
.
pumpWidget
(
new
FutureBuilder
<
String
>(
key:
key
,
future:
null
,
builder:
snapshotText
,
initialData:
'I'
,
));
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.none, I, null)'
),
findsOneWidget
);
});
testWidgets
(
'ignores initialData when reconfiguring'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
new
GlobalKey
();
await
tester
.
pumpWidget
(
new
FutureBuilder
<
String
>(
key:
key
,
future:
null
,
builder:
snapshotText
,
initialData:
'I'
,
));
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.none, I, null)'
),
findsOneWidget
);
final
Completer
<
String
>
completer
=
new
Completer
<
String
>();
await
tester
.
pumpWidget
(
new
FutureBuilder
<
String
>(
key:
key
,
future:
completer
.
future
,
builder:
snapshotText
,
initialData:
'Ignored'
,
));
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.waiting, I, null)'
),
findsOneWidget
);
});
});
group
(
'StreamBuilder'
,
()
{
testWidgets
(
'gracefully handles transition from null stream'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -180,6 +208,33 @@ void main() {
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.done, 4, null)'
),
findsOneWidget
);
});
testWidgets
(
'runs the builder using given initial data'
,
(
WidgetTester
tester
)
async
{
final
StreamController
<
String
>
controller
=
new
StreamController
<
String
>();
await
tester
.
pumpWidget
(
new
StreamBuilder
<
String
>(
stream:
controller
.
stream
,
builder:
snapshotText
,
initialData:
'I'
,
));
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.waiting, I, null)'
),
findsOneWidget
);
});
testWidgets
(
'ignores initialData when reconfiguring'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
key
=
new
GlobalKey
();
await
tester
.
pumpWidget
(
new
StreamBuilder
<
String
>(
key:
key
,
stream:
null
,
builder:
snapshotText
,
initialData:
'I'
,
));
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.none, I, null)'
),
findsOneWidget
);
final
StreamController
<
String
>
controller
=
new
StreamController
<
String
>();
await
tester
.
pumpWidget
(
new
StreamBuilder
<
String
>(
key:
key
,
stream:
controller
.
stream
,
builder:
snapshotText
,
initialData:
'Ignored'
,
));
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.waiting, I, null)'
),
findsOneWidget
);
});
});
group
(
'FutureBuilder and StreamBuilder behave identically on Stream from Future'
,
()
{
testWidgets
(
'when completing with data'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -211,6 +266,24 @@ void main() {
]));
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.none, null, null)'
),
findsNWidgets
(
2
));
});
testWidgets
(
'when initialData is used with null Future and Stream'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
Column
(
children:
<
Widget
>[
new
FutureBuilder
<
String
>(
future:
null
,
builder:
snapshotText
,
initialData:
'I'
),
new
StreamBuilder
<
String
>(
stream:
null
,
builder:
snapshotText
,
initialData:
'I'
),
]));
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.none, I, null)'
),
findsNWidgets
(
2
));
});
testWidgets
(
'when using initialData and completing with data'
,
(
WidgetTester
tester
)
async
{
final
Completer
<
String
>
completer
=
new
Completer
<
String
>();
await
tester
.
pumpWidget
(
new
Column
(
children:
<
Widget
>[
new
FutureBuilder
<
String
>(
future:
completer
.
future
,
builder:
snapshotText
,
initialData:
'I'
),
new
StreamBuilder
<
String
>(
stream:
completer
.
future
.
asStream
(),
builder:
snapshotText
,
initialData:
'I'
),
]));
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.waiting, I, null)'
),
findsNWidgets
(
2
));
completer
.
complete
(
'hello'
);
await
eventFiring
(
tester
);
expect
(
find
.
text
(
'AsyncSnapshot(ConnectionState.done, hello, null)'
),
findsNWidgets
(
2
));
});
});
group
(
'StreamBuilderBase'
,
()
{
testWidgets
(
'gracefully handles transition from null stream'
,
(
WidgetTester
tester
)
async
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment