HiveError: The box "user" is already open and of type Box<User>
Solution 1
- You can open your
user
Box in themain
method of your app:
Future<void> main() async {
...
final appDocumentDirectory = await path_provider.getApplicationDocumentsDirectory();
Hive.init(appDocumentDirectory.path);
Hive.registerAdapter(UserAdapter());
// open the user box
await Hive.openBox('user');
_setUpLogging();
runApp(MultiProvider(providers: providers, child: StartupApplication()));
}
- Access the previously opened box like below:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// user box
Box userBox;
@override
void initState() {
super.initState();
// get the previously opened user box
userBox = Hive.box('user');
}
@override
Widget build(BuildContext context) {
// check for your conditions
return (userBox.values.isNotEmpty && userBox.get(0).active == 1)
? HomeView()
: Intro();
}
}
Solution 2
I've given Hive the first try and observing this.
If you open the box like this:
await Hive.openBox("MyModelBox");
It'll throw the exception:
Box not found. Did you forget to call Hive.openBox()?
Let's take a look in Box
:
BoxBase<E> _getBoxInternal<E>(String name, [bool? lazy]) {
var lowerCaseName = name.toLowerCase();
var box = _boxes[lowerCaseName];
if (box != null) {
if ((lazy == null || box.lazy == lazy) && box.valueType == E) {
return box as BoxBase<E>;
} else {
var typeName = box is LazyBox
? 'LazyBox<${box.valueType}>'
: 'Box<${box.valueType}>';
throw HiveError('The box "$lowerCaseName" is already open '
'and of type $typeName.');
}
} else {
throw HiveError('Box not found. Did you forget to call Hive.openBox()?');
}
}
The box.valueType
would be dynamic
,
the E
would be your class model type MyModel
. Thus they won't be equal.
But if you passing the particular type of model
await Hive.openBox<MyModel>("MyModelBox");
The error vanishes.
Solution 3
This happens because you have already defined another box with type User somewhere with the same name (using
final myBoxName = 'userBox';
Hive.openBox<User>(myBoxName);
and trying to open the box with the same name with another type e.g.
Hive.openBox<bool>(myBoxName);
So ofcourse flutter will have problem openning the box, as it is already there with another type.
You have to find where you are using different types & fix the problem by using different names.
DolDurma
Updated on December 18, 2022Comments
-
DolDurma over 1 year
I'm trying to use
Hive
inside flutterMobx
, after checking user data inHive
I switched to another screens such asHomeView
orIntro
main.dart
:Future<void> main() async { ... final appDocumentDirectory = await path_provider.getApplicationDocumentsDirectory(); Hive.init(appDocumentDirectory.path); Hive.registerAdapter(UserAdapter()); _setUpLogging(); runApp(MultiProvider(providers: providers, child: StartupApplication())); }
StartupApplication
class: I don't useHive
class StartupApplication extends StatelessWidget { @override Widget build(BuildContext context) { final isPlatformDark = WidgetsBinding.instance.window.platformBrightness == Brightness.dark; final initTheme = isPlatformDark ? nebrassLightTheme : nebrassLightTheme; return ThemeProvider( initTheme: initTheme, duration: const Duration(milliseconds: 400), child: Builder(builder: (context) { return MaterialApp( title: 'TEST', theme: ThemeProvider.of(context), home: const OverlaySupport(child: OKToast( child: MyHomePage() //--> checking user data widget )), onGenerateRoute: Routes.sailor.generator(), navigatorKey: Routes.sailor.navigatorKey, ); }), ); } }
checking
User
inHive
insideMyHomePage
class:class MyHomePage extends StatefulWidget { const MyHomePage({Key key}) : super(key: key); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return FutureBuilder<Box<User>>( future: Hive.openBox('user'), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { final Box<User> userBox = snapshot.data; if (userBox.values.isNotEmpty && userBox.get(0).active == 1) { return HomeView(); } else { return Intro(); } } else { return Container(); } }); } @override void dispose() { Hive.close(); super.dispose(); } }
now in other screen such as
RegisterScreen
class I implementedMobX
and inside that I want to useuser
box, for example:class Register extends StatefulWidget { @override _RegisterState createState() => _RegisterState(); } class _RegisterState extends State<Register> { TextEditingController _mobileNumber; final GlobalKey<ScaffoldState> _scaffoldState = GlobalKey<ScaffoldState>(); @override void initState() { super.initState(); _mobileNumber = TextEditingController(); } @override Widget build(BuildContext context) { final _registerViewModel = Provider.of<RegisterViewModel>(context, listen: false); return Directionality( textDirection: TextDirection.ltr, child: Scaffold( key: _scaffoldState, ... //_registerViewModel.registerAccount(_mobileNumber.text, '111'); ), ); } void _showSnackBar(String message, BuildContext context) { _scaffoldState.currentState.showSnackBar(SnackBar( content: Directionality( textDirection: TextDirection.rtl, child: Text( '$message', style: AppTheme.of(context).caption().copyWith(color: Colors.white), )))); } }
MobX
implementation:enum RegisterLoadingState { loading, done } enum ActiveLoadingState { loading, done } enum RegisteringState { initial, registered, activated, registerError, activeError } class RegisterViewModel = _RegisterViewModel with _$RegisterViewModel; abstract class _RegisterViewModel with Store { final WebApi _webApi; _RegisterViewModel({@required WebApi webApi}) : _webApi = webApi; ... @action Future<void> registerAccount(String mobileNumber, String deviceId) async { final RegisterRequest _request = RegisterRequest(mobileNumber, deviceId); try { loadingState = RegisterLoadingState.loading; final _res = await _webApi.register(_request); loadingState = RegisterLoadingState.done; _registerResponse = RegisterResponse.fromJson(_res.body as Map<String, dynamic>); /* I GET ERROR IN THIS LINE -- HiveError: The box "user" is already open and of type Box<User>.*/ final userBox = await Hive.openBox('user'); final user = User(/*...*/); userBox.putAt(0, user); } @action Future<void> activeAccount(String mobileNumber, String verifyCode) async { final ActiveAccountRequest _activeAccount = ActiveAccountRequest(mobileNumber, verifyCode); final userBox = await Hive.openBox('user'); final User currentUser = userBox.getAt(0) as User; final user = User(/*...*/); userBox.putAt(0, user); } }
-
void over 3 yearsYou are opening multiple
boxes
of the same typeUser
. What is the question here ? -
DolDurma over 3 years@void my question is how can i use previously opened box? i want to use box on different screens or how can i open again box?
-
void over 3 yearsYou can open a
Box
in themain
method of your app and access aBox
like =>Box userBox = Hive.box('user');
-
DolDurma over 3 years@void and how about after that? my mean is
MyHomePage
class -
void over 3 yearsI added an answer. Check it out.
-
-
DolDurma over 3 yearshow can i use
FutureBuilder
instead of opening box inmain
function? -
void over 3 yearsIf you want to use the
FutureBuilder
widget in theHomePage
, you can move the opening of box frommain
to theHomePage
and use aFutureBuilder
widget. @DolDurma -
void over 3 yearsDid you come across any other issues with my provided answer ?
-
DolDurma over 3 yearsI changed code and I don't get error now. But I don't want opening box in main function
-
void over 3 yearsLike I said in my previous comment, you can move opening of
box
toHomePage
and use aFutureBuilder
widget. @DolDurma -
DolDurma over 3 yearsLet us continue this discussion in chat.