What is hive?
Hive is a form of local database storage, Hive is organized as boxes. Each Box can be considered to correspond to an SQL Table, but it is data storage of unstructured form (NoSQL) ie type < key, value >
and can store any data type.
Open Box in Hive
To use a Box, you must open the Box to use it.
1 2 | var box = await Hive.openBox<E>('testBox'); |
This method is extremely useful in Flutter because it can be called anywhere without having to pass between widgets.
But if Box is already open, the above code will be disabled and the internal parameters will be ignored.
Once opened Box can proceed to Read, Write, Delete the elements in it.
The parameters that a Box will have are as follows:
Parameter | description |
---|---|
name | The name of the Box specified the storage location and is used to check if the box already exists. |
encryptionKey | Used to store encrypted and decoded data of Box but must be 32 byte array. |
keyComparator | By default, the keys are sorted alphabetically. This parameter allows you to provide a custom sort order of your choice. |
compactionStrategy | Specify your compression rule and Hive will compress according to that rule. |
crashRecovery | If your application is disabled while the write operation is running, the last item may be corrupted. This item will be automatically deleted when the application starts again. If you do not want this behavior, you can disable it. |
path | By default, the boxes are stored in the directory provided Hive.init () . With this parameter, you can specify the location where Box will be stored. |
bytes | You can supply Box in binary form and open Box in memory. |
E | The optional type parameter specifies the type of values in the Box. |
Read, Write, Delete in Hive
Read in Hive
Because the boxes in Hive use the <key, value> query type, just call the key to get the corresponding data:
1 2 3 4 5 6 7 8 9 | // Mở Box people. var box = Hive.box('people'); // get giá trị theo key là name. String name = box.get('name'); //get giá trị theo key là birthday. DateTime birthday = box.get('birthday'); |
If the key does not exist, it returns null. Optionally, you can specify the defaultValue to be returned in case the key does not exist.
1 2 | double height = box.get('randomKey', defaultValue: 17.5); |
Write in Hive
Writing to Box is like writing to Map <key, value>. All keys must be ASCII strings with a maximum length of 255 characters or unsigned 32-bit integers.
1 2 3 4 5 6 7 8 9 10 | var box = Hive.box('myBox'); box.put('name', 'Paul'); box.put('friends', ['Dave', 'Simon', 'Lisa']); box.put(123, 'test'); box.putAll({'key1': 'value1', 42: 'life'}) |
One advantage of Hive is that updates are instantaneous without the use of async
in Flutter, and if you want to be sure to get data, you can add the await
of the Future
class.
1 2 3 4 5 6 7 8 9 10 11 12 13 | var box = await Hive.openBox('box'); box.put('key', 'value'); print(box.get('key')); // value var lazyBox = await Hive.openLazyBox('lazyBox'); var future = lazyBox.put('key', 'value'); print(lazyBox.get('key')); // null await future; print(lazyBox.get('key')); // value |
With lazyBox
if the get data fails, it will return null
while adding await with future
will return the old value.
Delete in Hive
Hive provides methods to implement Delete.
1 2 3 | contactsBox.deleteAt(index); contactsBox.deleteAll(interible); |
Hive in the simple Flutter app
I will write an app that features:
- Add a new contact,
- Delete contact by index.
- Display saved contacts.
Add Hive library
Go to pubspec.yaml
file and add the following paragraph.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | dependencies: flutter: sdk: flutter cupertino_icons: ^0.1.3 hive: ^1.4.1+1 hive_flutter: ^0.3.0+2 path_provider: ^1.6.5 dev_dependencies: hive_generator: ^0.7.0+2 build_runner: ^1.10.0 flutter_test: sdk: flutter dependency_overrides: quiver: 2.1.3 |
Init Hive into the App
The hive needs to be initialized, indicating the path in which folder it stores data. It is best to initialize Hive right in the main()
1 2 3 4 5 6 7 | void main() async{ WidgetsFlutterBinding.ensureInitialized(); final appDocumentDirectory = await path_provider.getApplicationDocumentsDirectory(); Hive.init(appDocumentDirectory.path); runApp(MyApp()); } |
And to prevent unnecessary data from loading on RAM when exiting the app, you should close () Hive again.
1 2 3 4 5 6 | @override void dispose() { Hive.close(); super.dispose(); } |
Create a Contacts
class
1 2 3 4 5 6 7 | class Contact { final String name; final int age; Contact(this.name, this.age); } |
Create a ContactPage Widgets where will display a list of saved contacts.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | class ContactPage extends StatelessWidget { const ContactPage({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Page Hive'), ), body: Column( children: <Widget>[Expanded(child: _buildListView()), NewContactForm()], ), ); } Widget _buildListView() { return WatchBoxBuilder( box: Hive.box('contacts'), builder: (context, contactsBox) { return ListView.builder( itemCount: contactsBox.length, itemBuilder: (BuildContext context, int index) { final contact = contactsBox.getAt(index) as Contact; return ListTile( title: Text(contact.name), subtitle: Text(contact.numberCall.toString()), trailing: Row( mainAxisSize: MainAxisSize.min, children: <Widget>[ IconButton( icon: Icon(Icons.refresh), onPressed: () { //Sửa tên liên hệ. contactsBox.putAt( index, Contact('${contact.name}*', contact.numberCall) ); }, ), IconButton( icon: Icon(Icons.delete), onPressed: () { //Xoá liên hệ theo index. contactsBox.deleteAt(index); }, ) ],), ); }, ); }, ); } } |
WatchBoxBuilder()
is a Widgets of package flutter_hive used to update UI when there is a change of Box.
To add a new contact, create a new Widgets new_contact_form.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ... void addContact(Contact contact) { final contactsBox = Hive.box('contacts'); // phương thức add() sẽ tự động tăng key lên +1 mỗi khi có liên hệ được thêm vào. contactsBox.add(contact); } ... RaisedButton( child: Text('Add New Contact'), onPressed: () { _formKey.currentState.save(); final newContact = Contact(_name, int.parse(_age)); addContact(newContact); }, ) ... |
Because Hive requires to save data as Json, the contactsBox.add () method wants to do it, in the main()
function, we have to add another Adapter
.
1 2 3 4 5 6 7 8 9 10 | void main() async{ WidgetsFlutterBinding.ensureInitialized(); final appDocumentDirectory = await path_provider.getApplicationDocumentsDirectory(); Hive.init(appDocumentDirectory.path); Hive.registerAdapter(ContactAdapter()); runApp(MyApp()); } |
Steps to create the Adapter:
Go to the Contact class and add annotations, HiveType will be for the class and HiveField will be for properties of that class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //chỉ ra path để lưu Adapter part 'contact.g.dart'; @HiveType(typeId: 0) class Contact { @HiveField(0) final String name; @HiveField(1) final int numberCall; Contact(this.name, this.numberCall); } |
Typing the following command to flutter will automatically generate an adapter file for us:
> flutter packages pub run build_runner build
As a result, we get a contact.g.dart
file with the following content:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // GENERATED CODE - DO NOT MODIFY BY HAND part of 'contact.dart'; // ************************************************************************** // TypeAdapterGenerator // ************************************************************************** class ContactAdapter extends TypeAdapter<Contact> { @override final typeId = 0; @override Contact read(BinaryReader reader) { var numOfFields = reader.readByte(); var fields = <int, dynamic>{ for (var i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return Contact( fields[0] as String, fields[1] as int, ); } @override void write(BinaryWriter writer, Contact obj) { writer ..writeByte(2) ..writeByte(0) ..write(obj.name) ..writeByte(1) ..write(obj.numberCall); } } |
Finally build on your phone to test it:
So I have finished introducing Hive. Thank you to everyone for watching this hope that helped everyone.
Link code
You can read more here:
https://docs.hivedb.dev/#/basics/hive_in_flutter?id=initialize-flutter-apps