1

我正在使用sqflite数据库来保存用户列表。我有用户列表屏幕,它显示用户列表,它有一个 fab 按钮,单击 fab 按钮,用户被重定向到下一个屏幕,他可以在其中将新用户添加到数据库。新用户已正确插入数据库,但当用户按下后退按钮并返回用户列表屏幕时,新添加的用户在屏幕上不可见。我必须关闭应用程序并重新打开它,然后新添加的用户会在屏幕上可见。

我正在使用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

4

3 回答 3

2

从评论中跟进,您似乎在这两个页面中没有一个 UsersBloc 实例。HomePage 和 UserDetails 都返回一个 BlocProvider 实例化一个 UsersBloc 实例。因为您有两个 blocs 实例(您不应该有),所以您没有正确更新流。

解决方案是从这两个页面(HomePage 和 UserDetail)中删除 BlocProvider 并将 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(),
    );
  }
}

也从 UserDetail 中删除 BlocProvider。在 UsersBloc 中,在插入用户后,在 insertUser() 方法中调用 fetchUser(),以重新查询数据库并更新用户流。

同样正如 Rémi Rousselet 所说,使用返回先前值的主题之一。

于 2019-01-25T11:22:41.017 回答
0

问题是您使用的是PublishSubject.

当一个新的监听器订阅 aPublishSubject时,它不会收到之前发送的值,只会接收下一个事件。

最简单的解决方案是使用 aBehaviorSubject或 aReplaySubject代替。这两个将直接用最新的值调用他们的监听器。

于 2019-01-25T10:34:20.363 回答
0
@override
  void initState() {
    super.initState();
    userBloc = BlocProvider.of<UserBloc>(context);
    userBloc.fetchUser();
  }

问题是您在页面的 initState 中调用了 userBloc.fetchUser() 函数。

每当向其中添加新数据时,Bloc 流就会发出,而 userBloc.fetchUser() 函数正是这样做的,它添加了您从 Sqflite 数据库中获取的 userList。

每当您从添加用户屏幕返回用户列表屏幕时,都不会调用 init 函数。它仅在创建用户列表屏幕时调用,即,每当您将其推送到导航堆栈时。

解决方法是在 StreamBuilder 的快照数据为空时调用 userBloc.fetchUser()。

...
 if (!snapshot.hasData) {
      userBloc.fetchUser();
        return Center(
          child: CircularProgressIndicator(),
        );
      }
...
于 2019-01-25T11:25:08.697 回答