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

无法获取新Hive Box,登出重登报错:Box已关闭

问题分析与解决方案

问题根源

登出时调用Hive.close()会关闭所有已打开的Box实例,但全局的CardsDataBase(Provider单例)仍持有之前被关闭的Box引用。重新登录后虽然打开了新的Box,但CardsDataBase没有更新内部的_myBox指向新实例,导致UI访问的还是已关闭的旧Box,触发Box has already been closed错误。

具体修改步骤

1. 登录时主动通知数据库更新Box实例

修改登录方法,打开新Box后立即更新CardsDataBase的引用:

Future signInWithEmailAndPassword(String email, String password) async {
    try {
      UserCredential result = await _auth.signInWithEmailAndPassword(email: email, password: password);
      User? user = result.user;
      if(user == null) return null;
      
      prefs!.setString(AppConstants.kBoxPreferenceKey, user.uid);
      await Hive.openBox(user.uid);
      
      // 通知数据库更新当前Box
      final dbProvider = Provider.of<CardsDataBase>(context, listen: false);
      dbProvider.updateCurrentBox();
      
      return user;
    } catch (error) {
      print(error.toString());
      return null;
    }
} 

2. 重构CardsDataBase,增加Box状态校验与更新逻辑

优化内部引用管理,确保每次访问的都是有效打开的Box:

class CardsDataBase extends ChangeNotifier {
  Box? _myBox; // 改为可空类型,避免未初始化风险
  
  // 访问时自动校验Box状态,失效则重新获取
  Box get myBox {
    if(_myBox == null || !_myBox!.isOpen) {
      final boxName = prefs!.getString(AppConstants.kBoxPreferenceKey)!;
      _myBox = Hive.box(boxName);
    }
    return _myBox!;
  }

  CardsDataBase() {
    initBox();
  }

  void initBox() {
    final boxName = prefs!.getString(AppConstants.kBoxPreferenceKey);
    if(boxName != null) {
      _myBox = Hive.box(boxName);
    }
    notifyListeners();
  }

  // 新增:更新当前Box实例
  void updateCurrentBox() {
    final boxName = prefs!.getString(AppConstants.kBoxPreferenceKey)!;
    _myBox = Hive.box(boxName);
    notifyListeners();
  }

  // 重置Box引用(登出时调用)
  void resetBox() {
    _myBox = null;
    notifyListeners();
  }

  void deleteFolder(String folderName) {
    myBox.delete(folderName); // 直接使用校验后的myBox
    notifyListeners();
  }

  void updateDataBase(String listName, List listContent) {
    myBox.put(listName, listContent);
    notifyListeners();
  }
}

3. 登出时重置数据库的Box引用

修改登出方法,清空CardsDataBase的旧Box引用:

Future signOut() async {
    prefs!.remove(AppConstants.kBoxPreferenceKey);
    await Hive.close();
    
    // 重置数据库的Box引用
    final dbProvider = Provider.of<CardsDataBase>(context, listen: false);
    dbProvider.resetBox();
    
    try {
      return await _auth.signOut();
    } catch (error) {
      print(error.toString());
      return null;
    }
}

4. UI层增加Box状态校验

在LibraryScreen中先检查Box状态,避免无效访问:

@override
Widget build(BuildContext context) {
  final provider = Provider.of<CardsDataBase>(context);

  // Box未打开时显示加载/空状态
  if(!provider.myBox.isOpen) {
    return const Center(child: CircularProgressIndicator());
  }

  Iterable listOfKeysFromBox = provider.myBox.keys;

  List<FolderWidget> folderWidgetsList = listOfKeysFromBox.map((e)=>
    FolderWidget(folderName: e, folderLocation: FolderLocation.downloaded, folderContents: provider.myBox.get(e))
  ).toList();

  List<StatelessWidget> listForDownloadedColumn = [
    const Text('Downloaded Folders',
        style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700)),
    const MyDivider(),
  ];
  listForDownloadedColumn.addAll(folderWidgetsList);

  return Scaffold(...);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:06:14