Блок-шаблон не отображает нового пользователя в sqflite на экране

Я использую sqflite База данных для сохранения списка пользователей. У меня есть экран со списком пользователей, который показывает список пользователей, и у него есть потрясающая кнопка, при нажатии на кнопку потрясающего пользователя, пользователь перенаправляется на следующий экран, где он может добавить нового пользователя в базу данных. Новый пользователь правильно вставлен в базу данных, но когда пользователь нажимает кнопку "Назад" и возвращается на экран списка пользователей, вновь добавленный пользователь не отображается на экране. Я должен закрыть приложение и открыть его снова, тогда вновь добавленный пользователь виден на экране.

я использую bloc шаблон и следующий мой код для отображения списка пользователей

class _UserListState extends State<UserList> {
  UserBloc userBloc;

  @override
  void initState() {
    super.initState();
    userBloc = BlocProvider.of<UserBloc>(context);
    userBloc.fetchUser();
  }

  @override
  void dispose() {
    userBloc?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(

      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.of(context).pushNamed("/detail");
        },
        child: Icon(Icons.add),
      ),
      body: StreamBuilder(
        stream: userBloc.users,
        builder: (context, AsyncSnapshot<List<User>> snapshot) {
          if (!snapshot.hasData) {
            return Center(
              child: CircularProgressIndicator(),
            );
          }

          if (snapshot.data != null) {
            return ListView.builder(
              itemBuilder: (context, index) {
                return Dismissible(
                  key: Key(snapshot.data[index].id.toString()),
                  direction: DismissDirection.endToStart,
                  onDismissed: (direction) {
                    userBloc.deleteParticularUser(snapshot.data[index]);
                  },
                  child: ListTile(
                    onTap: () {
                      Navigator.of(context).push(MaterialPageRoute(
                          builder: (context) => UserDetail(
                               user: snapshot.data[index],
                              )));
                    },
                    title: Text(snapshot.data[index].name),
                    subtitle:
                        Text("Mobile Number ${snapshot.data[index].userId}"),
                    trailing:
                        Text("User Id ${snapshot.data[index].mobileNumber}"),
                  ),
                );
              },
              itemCount: snapshot.data.length,
            );
          }
        },
      ),
    );
  }
}

Ниже приведен мой код блока

    class UserBloc implements BlocBase {
  final _users = BehaviorSubject<List<User>>();

  Observable<List<User>> get users => _users.stream;

  fetchUser() async {
    await userRepository.initializeDatabase();

    final users = await userRepository.getUserList();
    _users.sink.add(users);
  }

  insertUser(String name,int id,int phoneNumber) async {
    userRepository.insertUser(User(id, name, phoneNumber));
    fetchUser();
  }

  updateUser(User user) async {
    userRepository.updateUser(user);
  }

  deleteParticularUser(User user) async {
    userRepository.deleteParticularUser(user);
  }

  deleteAllUser() {
    return userRepository.deleteAllUsers();
  }

  @override
  void dispose() {
    _users.close();
  }
}

Поскольку Реми отправил ответ, говоря, что я должен попробовать BehaviorSubject а также ReplaySubject что я пробовал, но это не помогает. Я также позвонил fetchUser(); внутри insertUser() как указано в комментариях

Ниже приведена ссылка на полный пример

https://github.com/pritsawa/sqflite_example

3 ответа

Решение

Следите за комментариями, кажется, у вас нет ни одного экземпляра вашего UsersBloc на этих двух страницах. И HomePage, и UserDetails возвращают BlocProvider, который создает экземпляр UsersBloc. Поскольку у вас есть два экземпляра блоков (которых у вас не должно быть), вы не обновляете потоки должным образом.

Решение состоит в том, чтобы удалить BlocProvider с этих двух страниц (HomePage и UserDetail) и обернуть в него виджет MaterialApp, чтобы сделать один и тот же экземпляр доступным для обеих страниц.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      bloc: UserBloc(),
      child:MaterialApp(...

Домашняя страница будет:

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return UserList(),
    );
  }
}

Удалите BlocProvider и из UserDetail. Затем в UsersBloc вызовите fetchUser() внутри метода insertUser() после вставки пользователя, чтобы запросить базу данных и обновить поток пользователей.

Также, как сказал Реми Русселе, используйте один из предметов, которые возвращают предыдущие значения.

Проблема в том, что вы используете PublishSubject,

Когда новый слушатель подписывается на PublishSubject, он не получит ранее отправленное значение и получит только следующие события.

Самое простое решение - использовать BehaviorSubject или ReplaySubject вместо. Эти два будут напрямую вызывать своего слушателя с последними значениями.

@override
  void initState() {
    super.initState();
    userBloc = BlocProvider.of<UserBloc>(context);
    userBloc.fetchUser();
  }

Проблема в том, что вы вызвали функцию userBloc.fetchUser() в initState страницы.

Блок-поток генерируется всякий раз, когда к нему добавляются новые данные, а функция userBloc.fetchUser() делает именно это, добавляет список пользователей, который вы выбираете из базы данных Sqflite.

Всякий раз, когда вы возвращаетесь на экран списка пользователей с экрана добавления пользователя, функция init НЕ вызывается. Он вызывается только при создании экрана списка пользователей, то есть всякий раз, когда вы помещаете его в стек навигации.

Обходной путь должен вызывать userBloc.fetchUser() всякий раз, когда данные снимка вашего StreamBuilder нулевые.

...
 if (!snapshot.hasData) {
      userBloc.fetchUser();
        return Center(
          child: CircularProgressIndicator(),
        );
      }
...
Другие вопросы по тегам