You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过StateNotifier/ChangeNotifier修改Hive中InappPengguna的状态值

问题

我通过Hive Box存储用于离线自动登录的用户信息类InappPengguna,在登录页将其status设置为UserStatus.loggedinSuccessfully。进入主页后,希望将InappPengguna.status的值修改为UserStatus.loggedin,但代码执行后状态并未变更,仍为UserStatus.loggedinSuccessfully。

预期行为
Login [UserStatus.loggedinSuccessfully] -> Home [UserStatus.loggedinSuccessfully -> UserStatus.loggedin]

实际行为
Login [UserStatus.loggedinSuccessfully] -> Home [UserStatus.loggedinSuccessfully -> UserStatus.loggedinSuccessfully]

相关代码

RepoInapp 与 Provider

class RepoInapp extends ChangeNotifier {
  final KontrolerDB db; // class for Hive.init()

  RepoInapp(this.db);

  InappPengguna getDataInapp() {
    final ip = db.boxInapp.get('inapp');
    return ip as InappPengguna;
  }

  Future<void> saveDataInapp(InappPengguna ip) async {
    await db.boxInapp.put('inapp', ip);
    notifyListeners();
  }
}

final repoInappProvider = ChangeNotifierProvider((ref) {
  final db = ref.watch(providerDB);
  return RepoInapp(db);
});

状态修改相关代码

class ChangeLoginStatusNotifier extends StateNotifier<InappPengguna> {
  ChangeLoginStatusNotifier(this.ip) : super(ip);

  final InappPengguna ip;

  changeStatus() async {
    state = ip;
    if (state.status != UserStatus.loggedin) {
      state.status = UserStatus.loggedin;
    }
    return state;
  }
}

final providerUbahStatusMasuk =
    StateNotifierProvider<ChangeLoginStatusNotifier, InappPengguna>((ref) {
  final ri = ref.read(repoInappProvider);
  return ChangeLoginStatusNotifier(ri.getDataInapp());
});

@HiveType(typeId: 4)
enum UserStatus {
  @HiveField(0)
  loggedin,
  @HiveField(1)
  loggedout,
  @HiveField(2)
  loggedinSuccessfully,
  @HiveField(3)
  loggedinFailure
}

@HiveType(typeId: 2)
class InappPengguna {
  @HiveField(0)
  PenggunaInapp? pengguna;
  @HiveField(1)
  DateTime? loginLama;
  @HiveField(2)
  DateTime? loginBaru;
  @HiveField(3)
  UserStatus? status;
  @HiveField(4)
  String? token;

  InappPengguna(
      {this.pengguna, this.loginLama, this.loginBaru, this.status, this.token});

      // parsing function from/to json
}

解决方案

问题核心在于未正确处理Hive的持久化规则,以及StateNotifier的状态更新逻辑,以下是修正步骤:

1. 修正StateNotifier的状态更新逻辑

StateNotifier需要通过替换整个state对象触发监听者更新,直接修改对象内部属性无法触发UI刷新。同时必须调用Repo的保存方法,将修改同步到Hive Box。

修改后的ChangeLoginStatusNotifier:

class ChangeLoginStatusNotifier extends StateNotifier<InappPengguna> {
  final RepoInapp repoInapp;

  // 注入RepoInapp用于持久化操作
  ChangeLoginStatusNotifier(this.repoInapp, InappPengguna initialIp) : super(initialIp);

  Future<void> changeStatus() async {
    // 创建对象副本,避免直接修改原对象(符合Hive不可变操作的推荐规范)
    final updatedIp = InappPengguna(
      pengguna: state.pengguna,
      loginLama: state.loginLama,
      loginBaru: state.loginBaru,
      status: UserStatus.loggedin,
      token: state.token,
    );
    
    // 将修改后的对象保存到Hive Box
    await repoInapp.saveDataInapp(updatedIp);
    // 更新StateNotifier的state,触发UI监听更新
    state = updatedIp;
  }
}

// 调整Provider,注入RepoInapp实例
final providerUbahStatusMasuk = StateNotifierProvider<ChangeLoginStatusNotifier, InappPengguna>((ref) {
  final repo = ref.read(repoInappProvider);
  final initialIp = repo.getDataInapp();
  return ChangeLoginStatusNotifier(repo, initialIp);
});

2. 确保Hive序列化正常

如果InappPengguna尚未生成Hive Adapter,需要运行以下命令生成:

flutter packages pub run build_runner build

缺少Adapter会导致Hive无法正确持久化对象修改。

3. 主页调用修改方法

在主页中通过Provider调用状态修改方法:

// 在Home页面的Widget中使用ref调用
final statusNotifier = ref.read(providerUbahStatusMasuk.notifier);
await statusNotifier.changeStatus();

完成以上修改后,状态会正确同步到Hive Box,同时触发UI更新,实现预期的状态流转。

内容的提问来源于stack exchange,提问作者pras

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 15:43:15