HiveError: The box "user" is already open and of type Box<User>
HiveError: The box "user" is already open and of type Box<User>
我正在尝试在 flutter Mobx
中使用 Hive
,在 Hive
中检查用户数据后,我切换到另一个屏幕,例如 HomeView
或 Intro
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: 我不用Hive
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,
);
}),
);
}
}
检查 User
in Hive
inside MyHomePage
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();
}
}
现在在其他屏幕中,例如 RegisterScreen
class 我实现了 MobX
并且在其中我想使用 user
框,例如:
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
实施:
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);
}
}
- 您可以在应用的
main
方法中打开 user
盒子:
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()));
}
- 访问之前打开的框,如下所示:
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();
}
}
我已经第一次尝试并观察了 Hive。
如果你这样打开盒子:
await Hive.openBox("MyModelBox");
它会抛出异常:
Box not found. Did you forget to call Hive.openBox()?
我们来看看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()?');
}
}
box.valueType
将是 dynamic
,
E
将是您的 class 模型类型 MyModel
。因此它们不会相等。
但是如果你传递特定类型的模型
await Hive.openBox<MyModel>("MyModelBox");
错误消失。
发生这种情况是因为您已经在某处定义了另一个具有相同名称的 User 类型的框(使用
final myBoxName = 'userBox';
Hive.openBox<User>(myBoxName);
并尝试用另一种类型打开同名的盒子
例如
Hive.openBox<bool>(myBoxName);
所以当然 flutter 打开盒子会有问题,因为它已经有了另一种类型。
您必须找到使用不同类型的位置并使用不同的名称来解决问题。
我正在尝试在 flutter Mobx
中使用 Hive
,在 Hive
中检查用户数据后,我切换到另一个屏幕,例如 HomeView
或 Intro
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: 我不用Hive
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,
);
}),
);
}
}
检查 User
in Hive
inside MyHomePage
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();
}
}
现在在其他屏幕中,例如 RegisterScreen
class 我实现了 MobX
并且在其中我想使用 user
框,例如:
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
实施:
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);
}
}
- 您可以在应用的
main
方法中打开user
盒子:
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()));
}
- 访问之前打开的框,如下所示:
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();
}
}
我已经第一次尝试并观察了 Hive。
如果你这样打开盒子:
await Hive.openBox("MyModelBox");
它会抛出异常:
Box not found. Did you forget to call Hive.openBox()?
我们来看看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()?');
}
}
box.valueType
将是 dynamic
,
E
将是您的 class 模型类型 MyModel
。因此它们不会相等。
但是如果你传递特定类型的模型
await Hive.openBox<MyModel>("MyModelBox");
错误消失。
发生这种情况是因为您已经在某处定义了另一个具有相同名称的 User 类型的框(使用
final myBoxName = 'userBox';
Hive.openBox<User>(myBoxName);
并尝试用另一种类型打开同名的盒子 例如
Hive.openBox<bool>(myBoxName);
所以当然 flutter 打开盒子会有问题,因为它已经有了另一种类型。
您必须找到使用不同类型的位置并使用不同的名称来解决问题。