Flutter:使用2个嵌套的StreamBuilder,其中之一无法按预期工作

时间:2018-11-21 15:25:32

标签: stream flutter

我正在使用2个StreamBuilders(一个在另一个内)在App和App中进行构建。 最外面的一个消耗.Main-buttonWrapper并渲染该列表。 内层消耗Stream<List<User>>,在这里我可以检查用户是否喜欢。

代码如下:

users_page.dart

Stream<User>

users_block.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);
      });
  });
}

外部流被调用一次,并且onPressed方法也被调用一次(如预期的那样)。

但是我遇到的问题是,当我按下Icon时:userBloc会打印N次(其中N是列表中的行数),就像我会连续按下Icon一样。

所以日志是:

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);
    });
  }
}

在这种情况下,操作(按图标)执行一次,但是userBloc获得N次输入。

为什么会这样,我该如何解决这个问题?

谢谢!

1 个答案:

答案 0 :(得分:0)

我在定义的地方进行了测试:

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);
            }));
      },
    )
  ],
);

流:

_outState = _userSubject.switchMap<int>(
  (integer) {
    print("Input (sink): " + integer.toString());
    return doSomething(integer);
  },
);

当我运行此代码并单击IconButton 1时,输出为:

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

如您所见,打印“输入(接收器):1”显示了两次。 因此,对于接收器的任何输入,主题内的代码将执行n次,具体取决于订阅流的StreamBuilders的数量。

这种行为还好吗,还是一个错误?

我知道应该两次调用builder函数,因为流中的任何更改都将转发给所有订阅的StreamBuilder,但是主题内的代码也应该被调用两次?