Flutter: использование 2-х вложенных StreamBuilders, где один из них не работает должным образом - PullRequest
0 голосов
/ 21 ноября 2018

Я строю и приложение, где я использую 2 StreamBuilders (один внутри другого).Внешний использует Stream<List<User>> и отображает этот список.Внутренний использует Stream<User>, где я могу проверить, является ли пользователь любимым или нет.

Вот код:

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

Внешний поток вызывается один раз, а метод onPressed вызывается также один раз (как и ожидалось).

Ноу меня проблема, когда я нажимаю на иконку: userBloc печатает N раз (где N - количество строк в списке), как я бы нажимал на иконку N раз.

Итак, журнал:

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

В этом случае действие (нажатие на значок) выполняется один раз, но userBloc получает ввод N.

Почему это происходит и как я могу решить эту проблему?

Заранее спасибо!

1 Ответ

0 голосов
/ 26 ноября 2018

Я сделал тест, в котором я определил:

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, подписанных на поток.

Это поведение нормально, или это ошибка?

Я знаю, что функция построителя должна вызываться дважды, потому что любое изменение в потоке передается всем подписчикам StreamBuilder, но код внутри темы тоже должен вызываться дважды?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...