問題描述
嘗試在 Flutter 中訪問 Hive 數據庫時,“聯繫人”框已打開且類型為 Box (The box "contacts" is already open and of type Box when trying to access Hive database in flutter)
我在main中初始化box數據庫如下
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final appDocumentDirectory = await path_provider.getApplicationDocumentsDirectory();
Hive.init(appDocumentDirectory.path);
Hive.registerAdapter(ContactAdapter());
runApp(MyApp());
}
然後我使用FutureBuilder插件在material app中打開box如下:
FutureBuilder(
future: Hive.openBox<Contact>('contacts'),
builder: (context, snapshot) {
if(snapshot.connectionState == ConnectionState.done){
if(snapshot.hasError){
return Text(snapshot.error.toString() );
}
return ContactPage();
} else {
return Scaffold();
}
}
),
在ContactPage()裡面
我創建了這個:‑
ValueListenableBuilder(
valueListenable: Hive.box<Contact>('contacts').listenable(),
builder: (context,Box<Contact> box,_){
if(box.values.isEmpty){
return Text('data is empty');
} else {
return ListView.builder(
itemCount: box.values.length,
itemBuilder: (context,index){
var contact = box.getAt(index);
return ListTile(
title: Text(contact.name),
subtitle: Text(contact.age.toString()),
);
},
);
}
},
)
當我運行應用程序時出現以下錯誤
The following HiveError was thrown while handling a gesture: The box "contacts" is already open and of type Box<Contact>.
當我嘗試使用該框時不打開它,我得到錯誤意味著盒子沒有打開。
我必須使用盒子而不在 ValueListenableBuilder 中打開它嗎?但是我必須在不同的小部件中再次打開同一個框才能在其上添加數據。
參考解法
方法 1:
I'm jumping on this thread because I had a hard time trying to figure out how to deal with the deprecated WatchBoxBuilder while using the resocoder's Hive tutorial, and a google search led me here.
This is what I ended up using:
main.dart:
void main() async {
if (!kIsWeb) { // <‑‑ I put this here so that I could use Hive in Flutter Web
final dynamic appDocumentDirectory =
await path_provider.getApplicationDocumentsDirectory();
Hive.init(appDocumentDirectory.path as String);
}
Hive.registerAdapter(ContactAdapter());
runApp(child: MyApp());
}
and then ContactPage() (note: it's the same as OP's):
Widget _buildListView() {
return ValueListenableBuilder(
valueListenable: Hive.box<Contact>('contacts').listenable(),
builder: (context, Box<Contact> box, _) {
if (box.values.isEmpty) {
return Text('data is empty');
} else {
return ListView.builder(
itemCount: box.values.length,
itemBuilder: (context, index) {
var contact = box.getAt(index);
return ListTile(
title: Text(contact.name),
subtitle: Text(contact.age.toString()),
);
},
);
}
},
);
}
方法 2:
Its a simple explanation actually:
1. It only occurs when your box has a generic type like
Hive.openBox<User>('users')
2. So once you call Hive.box('users')
without specifying the generic type this error occurs.
THATS EVERYTHING.</p>
SOLUTION Hive.box<User>('users')
at each call :)
方法 3:
It is probably because you are trying to open the box inside FutureBuilder
. If somehow it tries to rebuild itself, it will try to open the box which is already opened. Can you try to open the box after you register the adapter like:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final appDocumentDirectory = await path_provider.getApplicationDocumentsDirectory();
Hive.init(appDocumentDirectory.path);
Hive.registerAdapter(ContactAdapter());
await Hive.openBox<Contact>('contacts');
runApp(MyApp());
}
And instead of FutureBuilder
just return ContactPage
方法 4:
In main.dart file :
future: Hive.openBox('contacts'),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Text(snapshot.error.toString());
} else {
return ContactPage();
}
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
In ContactPage:
return WatchBoxBuilder(
box: Hive.box('contacts'),
builder: (context, contactBox) {
return ListView.builder(
itemCount: contactBox.length,
itemBuilder: (context, index) {
final contact = contactBox.getAt(index) as Contact;
return ListTile(
title: Text(contact.name),
subtitle: Text(contact.number),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
contactBox.putAt(
index,
Contact('${contact.name}*', contact.number),
);
},
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
contactBox.deleteAt(index);
},
),
],
),
);
},
);
},
);
It's OK to open the box in future call..
(by aboodrak、William Terrill、Ray Zion、Selim Kundakçıoğlu、Mhamza007)