Flutter: Using 2 nested StreamBuilders where one of them is not working as expected
up vote
0
down vote
favorite
I'm building and App where I'm using 2 StreamBuilders (one inside another).
The outer one consumes an Stream<List<User>>
and render that list.
The inner one consumes Stream<User>
where I can check if the user is favorite or not.
Here is the code:
users_page.dart
@override
Widget build(BuildContext context) {
return Scaffold(
child: StreamBuilder<List<User>>(
stream: userBloc.outList,
initialData: ,
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
final List<User> users = snapshot.data;
return buildList(users);
})
}
Widget buildList(List<User> users) {
return ListView.builder(
itemCount: users.length,
itemBuilder: (BuildContext context, int index) {
final User user = users[index];
return ListTile(
title: Text('${user.firstName}'),
trailing: buildFavoriteButton(user));
});
}
Widget buildFavoriteButton(User user) {
User oldUser = user;
return StreamBuilder<User>(
stream: userBloc.outFavorite,
initialData: oldUser,
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
final User newUser = snapshot.data;
if (oldUser.id == newUser.id) {
oldUser = newUser;
}
return IconButton(
icon: Icon(Icons.favorite, color: oldUser.isFavorite ? Colors.red : Colors.blueGrey),
onPressed: () {
print('onPressed: This is called once');
userBloc.inFavorite.add(newUser);
});
});
}
users_block.dart
class UserBloc {
final Repository _repository = Repository();
// More variables like the BehaviourSubject for outList and so on ...
final BehaviorSubject<User> _userFavoriteSubject = BehaviorSubject<User>();
Stream<User> _outFavorite = Stream.empty();
Stream<User> get outFavorite => _outFavorite;
Sink<User> get inFavorite => _userFavoriteSubject;
UserBloc() {
_outFavorite = _userFavoriteSubject.switchMap<User>((user) {
print('userBloc: This is called N times')
return user.isFavorite ? _repository.removeFromFavorite(user) : _repository.saveAsFavorite(user);
});
}
}
The outer stream is called once and the onPressed method is called once as well (as expected).
But the problem I'm having is when I press the Icon: userBloc prints N times (where N is the number of rows in the list), like I would pressed the Icon N times.
So the log is:
print: onPressed: This is called once
print: userBloc: This is called N times
print: userBloc: This is called N times
...
print: userBloc: This is called N times
In this case the action (pressing the icon) is executed once, but userBloc gets N inputs.
Why this is happening and how can I solve this problem?
Thanks in advance!
stream flutter
add a comment |
up vote
0
down vote
favorite
I'm building and App where I'm using 2 StreamBuilders (one inside another).
The outer one consumes an Stream<List<User>>
and render that list.
The inner one consumes Stream<User>
where I can check if the user is favorite or not.
Here is the code:
users_page.dart
@override
Widget build(BuildContext context) {
return Scaffold(
child: StreamBuilder<List<User>>(
stream: userBloc.outList,
initialData: ,
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
final List<User> users = snapshot.data;
return buildList(users);
})
}
Widget buildList(List<User> users) {
return ListView.builder(
itemCount: users.length,
itemBuilder: (BuildContext context, int index) {
final User user = users[index];
return ListTile(
title: Text('${user.firstName}'),
trailing: buildFavoriteButton(user));
});
}
Widget buildFavoriteButton(User user) {
User oldUser = user;
return StreamBuilder<User>(
stream: userBloc.outFavorite,
initialData: oldUser,
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
final User newUser = snapshot.data;
if (oldUser.id == newUser.id) {
oldUser = newUser;
}
return IconButton(
icon: Icon(Icons.favorite, color: oldUser.isFavorite ? Colors.red : Colors.blueGrey),
onPressed: () {
print('onPressed: This is called once');
userBloc.inFavorite.add(newUser);
});
});
}
users_block.dart
class UserBloc {
final Repository _repository = Repository();
// More variables like the BehaviourSubject for outList and so on ...
final BehaviorSubject<User> _userFavoriteSubject = BehaviorSubject<User>();
Stream<User> _outFavorite = Stream.empty();
Stream<User> get outFavorite => _outFavorite;
Sink<User> get inFavorite => _userFavoriteSubject;
UserBloc() {
_outFavorite = _userFavoriteSubject.switchMap<User>((user) {
print('userBloc: This is called N times')
return user.isFavorite ? _repository.removeFromFavorite(user) : _repository.saveAsFavorite(user);
});
}
}
The outer stream is called once and the onPressed method is called once as well (as expected).
But the problem I'm having is when I press the Icon: userBloc prints N times (where N is the number of rows in the list), like I would pressed the Icon N times.
So the log is:
print: onPressed: This is called once
print: userBloc: This is called N times
print: userBloc: This is called N times
...
print: userBloc: This is called N times
In this case the action (pressing the icon) is executed once, but userBloc gets N inputs.
Why this is happening and how can I solve this problem?
Thanks in advance!
stream flutter
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I'm building and App where I'm using 2 StreamBuilders (one inside another).
The outer one consumes an Stream<List<User>>
and render that list.
The inner one consumes Stream<User>
where I can check if the user is favorite or not.
Here is the code:
users_page.dart
@override
Widget build(BuildContext context) {
return Scaffold(
child: StreamBuilder<List<User>>(
stream: userBloc.outList,
initialData: ,
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
final List<User> users = snapshot.data;
return buildList(users);
})
}
Widget buildList(List<User> users) {
return ListView.builder(
itemCount: users.length,
itemBuilder: (BuildContext context, int index) {
final User user = users[index];
return ListTile(
title: Text('${user.firstName}'),
trailing: buildFavoriteButton(user));
});
}
Widget buildFavoriteButton(User user) {
User oldUser = user;
return StreamBuilder<User>(
stream: userBloc.outFavorite,
initialData: oldUser,
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
final User newUser = snapshot.data;
if (oldUser.id == newUser.id) {
oldUser = newUser;
}
return IconButton(
icon: Icon(Icons.favorite, color: oldUser.isFavorite ? Colors.red : Colors.blueGrey),
onPressed: () {
print('onPressed: This is called once');
userBloc.inFavorite.add(newUser);
});
});
}
users_block.dart
class UserBloc {
final Repository _repository = Repository();
// More variables like the BehaviourSubject for outList and so on ...
final BehaviorSubject<User> _userFavoriteSubject = BehaviorSubject<User>();
Stream<User> _outFavorite = Stream.empty();
Stream<User> get outFavorite => _outFavorite;
Sink<User> get inFavorite => _userFavoriteSubject;
UserBloc() {
_outFavorite = _userFavoriteSubject.switchMap<User>((user) {
print('userBloc: This is called N times')
return user.isFavorite ? _repository.removeFromFavorite(user) : _repository.saveAsFavorite(user);
});
}
}
The outer stream is called once and the onPressed method is called once as well (as expected).
But the problem I'm having is when I press the Icon: userBloc prints N times (where N is the number of rows in the list), like I would pressed the Icon N times.
So the log is:
print: onPressed: This is called once
print: userBloc: This is called N times
print: userBloc: This is called N times
...
print: userBloc: This is called N times
In this case the action (pressing the icon) is executed once, but userBloc gets N inputs.
Why this is happening and how can I solve this problem?
Thanks in advance!
stream flutter
I'm building and App where I'm using 2 StreamBuilders (one inside another).
The outer one consumes an Stream<List<User>>
and render that list.
The inner one consumes Stream<User>
where I can check if the user is favorite or not.
Here is the code:
users_page.dart
@override
Widget build(BuildContext context) {
return Scaffold(
child: StreamBuilder<List<User>>(
stream: userBloc.outList,
initialData: ,
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
final List<User> users = snapshot.data;
return buildList(users);
})
}
Widget buildList(List<User> users) {
return ListView.builder(
itemCount: users.length,
itemBuilder: (BuildContext context, int index) {
final User user = users[index];
return ListTile(
title: Text('${user.firstName}'),
trailing: buildFavoriteButton(user));
});
}
Widget buildFavoriteButton(User user) {
User oldUser = user;
return StreamBuilder<User>(
stream: userBloc.outFavorite,
initialData: oldUser,
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
final User newUser = snapshot.data;
if (oldUser.id == newUser.id) {
oldUser = newUser;
}
return IconButton(
icon: Icon(Icons.favorite, color: oldUser.isFavorite ? Colors.red : Colors.blueGrey),
onPressed: () {
print('onPressed: This is called once');
userBloc.inFavorite.add(newUser);
});
});
}
users_block.dart
class UserBloc {
final Repository _repository = Repository();
// More variables like the BehaviourSubject for outList and so on ...
final BehaviorSubject<User> _userFavoriteSubject = BehaviorSubject<User>();
Stream<User> _outFavorite = Stream.empty();
Stream<User> get outFavorite => _outFavorite;
Sink<User> get inFavorite => _userFavoriteSubject;
UserBloc() {
_outFavorite = _userFavoriteSubject.switchMap<User>((user) {
print('userBloc: This is called N times')
return user.isFavorite ? _repository.removeFromFavorite(user) : _repository.saveAsFavorite(user);
});
}
}
The outer stream is called once and the onPressed method is called once as well (as expected).
But the problem I'm having is when I press the Icon: userBloc prints N times (where N is the number of rows in the list), like I would pressed the Icon N times.
So the log is:
print: onPressed: This is called once
print: userBloc: This is called N times
print: userBloc: This is called N times
...
print: userBloc: This is called N times
In this case the action (pressing the icon) is executed once, but userBloc gets N inputs.
Why this is happening and how can I solve this problem?
Thanks in advance!
stream flutter
stream flutter
edited Nov 21 at 17:26
asked Nov 21 at 15:25
fitu
3518
3518
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
I made a test where I defined:
Widget buildBody() {
return Column(
children: <Widget>[
StreamBuilder<int>(
stream: userBloc.outState,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("Builder 1");
print("Snapshot 1: " + snapshot.data.toString());
return (IconButton(
icon: Icon(Icons.favorite, color: Colors.red),
onPressed: () {
print("onPressed 1");
userBloc.inEvents.add(1);
}));
},
),
StreamBuilder<int>(
stream: userBloc.outState,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("Builder 2");
print("Snapshot 2: " + snapshot.data.toString());
return (IconButton(
icon: Icon(Icons.favorite, color: Colors.red),
onPressed: () {
print("onPressed 2");
userBloc.inEvents.add(2);
}));
},
)
],
);
And the stream:
_outState = _userSubject.switchMap<int>(
(integer) {
print("Input (sink): " + integer.toString());
return doSomething(integer);
},
);
When I run this code and click the IconButton 1, this is the output:
I/flutter ( 3912): Builder 1
I/flutter ( 3912): Snapshot 1: 0
I/flutter ( 3912): Builder 2
I/flutter ( 3912): Snapshot 2: 0
I/flutter ( 3912): onPressed 1
I/flutter ( 3912): Input (sink): 1
I/flutter ( 3912): Input (sink): 1
I/flutter ( 3912): Builder 1
I/flutter ( 3912): Snapshot 1: 1
I/flutter ( 3912): Builder 2
I/flutter ( 3912): Snapshot 2: 1
As you can see the print "Input (sink): 1" is shown twice.
So for any input to the sink the code inside subject is executed n times, depending on the amount of StreamBuilders subscribed to the stream.
Is this behaviour okay, or is it a bug?
I know that the builder function should be call twice because any change in the stream is forwarded to all StreamBuilder subscribed, but the code inside the subject should be call twice too?
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
I made a test where I defined:
Widget buildBody() {
return Column(
children: <Widget>[
StreamBuilder<int>(
stream: userBloc.outState,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("Builder 1");
print("Snapshot 1: " + snapshot.data.toString());
return (IconButton(
icon: Icon(Icons.favorite, color: Colors.red),
onPressed: () {
print("onPressed 1");
userBloc.inEvents.add(1);
}));
},
),
StreamBuilder<int>(
stream: userBloc.outState,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("Builder 2");
print("Snapshot 2: " + snapshot.data.toString());
return (IconButton(
icon: Icon(Icons.favorite, color: Colors.red),
onPressed: () {
print("onPressed 2");
userBloc.inEvents.add(2);
}));
},
)
],
);
And the stream:
_outState = _userSubject.switchMap<int>(
(integer) {
print("Input (sink): " + integer.toString());
return doSomething(integer);
},
);
When I run this code and click the IconButton 1, this is the output:
I/flutter ( 3912): Builder 1
I/flutter ( 3912): Snapshot 1: 0
I/flutter ( 3912): Builder 2
I/flutter ( 3912): Snapshot 2: 0
I/flutter ( 3912): onPressed 1
I/flutter ( 3912): Input (sink): 1
I/flutter ( 3912): Input (sink): 1
I/flutter ( 3912): Builder 1
I/flutter ( 3912): Snapshot 1: 1
I/flutter ( 3912): Builder 2
I/flutter ( 3912): Snapshot 2: 1
As you can see the print "Input (sink): 1" is shown twice.
So for any input to the sink the code inside subject is executed n times, depending on the amount of StreamBuilders subscribed to the stream.
Is this behaviour okay, or is it a bug?
I know that the builder function should be call twice because any change in the stream is forwarded to all StreamBuilder subscribed, but the code inside the subject should be call twice too?
add a comment |
up vote
0
down vote
I made a test where I defined:
Widget buildBody() {
return Column(
children: <Widget>[
StreamBuilder<int>(
stream: userBloc.outState,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("Builder 1");
print("Snapshot 1: " + snapshot.data.toString());
return (IconButton(
icon: Icon(Icons.favorite, color: Colors.red),
onPressed: () {
print("onPressed 1");
userBloc.inEvents.add(1);
}));
},
),
StreamBuilder<int>(
stream: userBloc.outState,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("Builder 2");
print("Snapshot 2: " + snapshot.data.toString());
return (IconButton(
icon: Icon(Icons.favorite, color: Colors.red),
onPressed: () {
print("onPressed 2");
userBloc.inEvents.add(2);
}));
},
)
],
);
And the stream:
_outState = _userSubject.switchMap<int>(
(integer) {
print("Input (sink): " + integer.toString());
return doSomething(integer);
},
);
When I run this code and click the IconButton 1, this is the output:
I/flutter ( 3912): Builder 1
I/flutter ( 3912): Snapshot 1: 0
I/flutter ( 3912): Builder 2
I/flutter ( 3912): Snapshot 2: 0
I/flutter ( 3912): onPressed 1
I/flutter ( 3912): Input (sink): 1
I/flutter ( 3912): Input (sink): 1
I/flutter ( 3912): Builder 1
I/flutter ( 3912): Snapshot 1: 1
I/flutter ( 3912): Builder 2
I/flutter ( 3912): Snapshot 2: 1
As you can see the print "Input (sink): 1" is shown twice.
So for any input to the sink the code inside subject is executed n times, depending on the amount of StreamBuilders subscribed to the stream.
Is this behaviour okay, or is it a bug?
I know that the builder function should be call twice because any change in the stream is forwarded to all StreamBuilder subscribed, but the code inside the subject should be call twice too?
add a comment |
up vote
0
down vote
up vote
0
down vote
I made a test where I defined:
Widget buildBody() {
return Column(
children: <Widget>[
StreamBuilder<int>(
stream: userBloc.outState,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("Builder 1");
print("Snapshot 1: " + snapshot.data.toString());
return (IconButton(
icon: Icon(Icons.favorite, color: Colors.red),
onPressed: () {
print("onPressed 1");
userBloc.inEvents.add(1);
}));
},
),
StreamBuilder<int>(
stream: userBloc.outState,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("Builder 2");
print("Snapshot 2: " + snapshot.data.toString());
return (IconButton(
icon: Icon(Icons.favorite, color: Colors.red),
onPressed: () {
print("onPressed 2");
userBloc.inEvents.add(2);
}));
},
)
],
);
And the stream:
_outState = _userSubject.switchMap<int>(
(integer) {
print("Input (sink): " + integer.toString());
return doSomething(integer);
},
);
When I run this code and click the IconButton 1, this is the output:
I/flutter ( 3912): Builder 1
I/flutter ( 3912): Snapshot 1: 0
I/flutter ( 3912): Builder 2
I/flutter ( 3912): Snapshot 2: 0
I/flutter ( 3912): onPressed 1
I/flutter ( 3912): Input (sink): 1
I/flutter ( 3912): Input (sink): 1
I/flutter ( 3912): Builder 1
I/flutter ( 3912): Snapshot 1: 1
I/flutter ( 3912): Builder 2
I/flutter ( 3912): Snapshot 2: 1
As you can see the print "Input (sink): 1" is shown twice.
So for any input to the sink the code inside subject is executed n times, depending on the amount of StreamBuilders subscribed to the stream.
Is this behaviour okay, or is it a bug?
I know that the builder function should be call twice because any change in the stream is forwarded to all StreamBuilder subscribed, but the code inside the subject should be call twice too?
I made a test where I defined:
Widget buildBody() {
return Column(
children: <Widget>[
StreamBuilder<int>(
stream: userBloc.outState,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("Builder 1");
print("Snapshot 1: " + snapshot.data.toString());
return (IconButton(
icon: Icon(Icons.favorite, color: Colors.red),
onPressed: () {
print("onPressed 1");
userBloc.inEvents.add(1);
}));
},
),
StreamBuilder<int>(
stream: userBloc.outState,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("Builder 2");
print("Snapshot 2: " + snapshot.data.toString());
return (IconButton(
icon: Icon(Icons.favorite, color: Colors.red),
onPressed: () {
print("onPressed 2");
userBloc.inEvents.add(2);
}));
},
)
],
);
And the stream:
_outState = _userSubject.switchMap<int>(
(integer) {
print("Input (sink): " + integer.toString());
return doSomething(integer);
},
);
When I run this code and click the IconButton 1, this is the output:
I/flutter ( 3912): Builder 1
I/flutter ( 3912): Snapshot 1: 0
I/flutter ( 3912): Builder 2
I/flutter ( 3912): Snapshot 2: 0
I/flutter ( 3912): onPressed 1
I/flutter ( 3912): Input (sink): 1
I/flutter ( 3912): Input (sink): 1
I/flutter ( 3912): Builder 1
I/flutter ( 3912): Snapshot 1: 1
I/flutter ( 3912): Builder 2
I/flutter ( 3912): Snapshot 2: 1
As you can see the print "Input (sink): 1" is shown twice.
So for any input to the sink the code inside subject is executed n times, depending on the amount of StreamBuilders subscribed to the stream.
Is this behaviour okay, or is it a bug?
I know that the builder function should be call twice because any change in the stream is forwarded to all StreamBuilder subscribed, but the code inside the subject should be call twice too?
answered 2 days ago
fitu
3518
3518
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53415296%2fflutter-using-2-nested-streambuilders-where-one-of-them-is-not-working-as-expec%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown