Hive database in Flutter - An overview
Hey folks out there,
Introduction
Hive database was designed with Flutter, a concept of Light-weight, blazingly fast, Local, NoSQL approach for developers written purely in Dart Programming language.
Advantages
Supports all platforms
No native dependencies required
Fast, light-weight, and efficient
Example Project: Book CRUD
Approach
Hive Box
Hive uses Box, an organized technique to store all the data. You can compare a Hive box with SQL table, but it does not have any structure and can contain anything.
Type Adapters
Type Adapter here acts as a convertor of Object to and from a binary form, since Hive uses primitive types such as List, Map, DateTime and Uint8List respectively.
Type Adapter needs to be generated, you can write yourself but the safest way is to generate them. Use hive_generator for that.
Since, we are using Book CRUD, we only have three fields,
id
book_title
book_author
Now, moving to the implementation part.
Adding packages
Before using Hive, we need to add some packages in “pubspec.yaml”
Add these in dependencies
hive: any
hive_flutter: any
Add these in dev_dependencies
hive_generator: any
build_runner: any
Now, initialize with this command under main() function
await Hive.initFlutter();
Next, open a Hive box
await Hive.openBox(‘booksbox’);
Now, add another file named “books.dart” and add this snippet
import 'package:hive/hive.dart';
part 'books.g.dart';
@HiveType(typeId: 1)
class Books {
Books({this.id,this.book_title,this.book_author});
@HiveField(0)
int? id;
@HiveField(1)
String? book_title;
@HiveField(2)
String? book_author;
}
You can see in the above snippet, each field annotated with @HiveField has a unique number and used to identify the fields.
Next, under the project terminal
Add this line flutter packages pub run build_runner build
It will generate TypeAdapters for books.
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'books.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class BooksAdapter extends TypeAdapter<Books> {
@override
final int typeId = 1;
@override
Books read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return Books()
..id = fields[0] as int
..book_title = fields[1] as String
..book_author = fields[2] as String;
}
@override
void write(BinaryWriter writer, Books obj) {
writer
..writeByte(3)
..writeByte(0)
..write(obj.id)
..writeByte(1)
..write(obj.book_title)
..writeByte(2)
..write(obj.book_author);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is BooksAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
In addition, now place this adapter in your main() method as
Hive.registerAdapter(BooksAdapter());
After adding, your main() function will look like this
Here, we conclude our database part.
User Interface(UI) Part
Create a new dart file as “my_books.dart” and add this snippet
import 'package:flutter/material.dart';
import 'package:hive_demo/Model/books.dart';
import 'package:hive_demo/main.dart';
import 'package:hive_flutter/adapters.dart';
class MyBooks extends StatefulWidget {
const MyBooks({Key? key}) : super(key: key);
@override
State<MyBooks> createState() => _MyBooksState();
}
class _MyBooksState extends State<MyBooks> {
final _title = TextEditingController();
final _author = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Hive DB"),
),
body: ValueListenableBuilder(
valueListenable: Hive.box<Books>('booksbox').listenable(),
builder: (context, Box<Books> box, _) {
if (box.values.isEmpty) {
return const Center(child: Text("No Books"));
} else {
return ListView.separated(
itemCount: box.values.length,
itemBuilder: (context, index) {
var result = box.getAt(index);
return Card(
child: ListTile(
title: Text(result!.book_title!),
subtitle: Text(result.book_author!),
trailing: InkWell(
child: const Icon(
Icons.remove_circle,
color: Colors.red,
),
onTap: () {
box.deleteAt(index);
},
),
),
);
},
separatorBuilder: (context, i) {
return const SizedBox(height: 12);
},
);
}
},
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () => addNewBook(context),
),
);
}
addNewBook(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text("New book"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
controller: _title,
decoration: const InputDecoration(hintText: 'Title'),
),
const SizedBox(
height: 15,
),
TextFormField(
controller: _author,
decoration: const InputDecoration(hintText: 'Author'),
),
const SizedBox(
height: 15,
),
ElevatedButton(
onPressed: () async {
await box!.put(
DateTime.now().toString(),
Books(
book_title: _title.text,
book_author: _author.text,
));
Navigator.pop(context);
},
child: const Text("Add")),
],
),
);
});
}
}
Next, for the “main.dart” file,
import 'package:flutter/material.dart';
import 'package:hive_demo/Model/books.dart';
import 'package:hive_demo/Screens/my_books.dart';
import 'package:hive_flutter/adapters.dart';
Box? box;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
box = await Hive.openBox<Books>("booksbox");
Hive.registerAdapter(BooksAdapter());
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
title: "Hive Demo",
home: MyBooks(),
);
}
}
After adding, run the app
Pic #1
Pic #2
Pic #3
So, this sums up the article.
I hope you have had a good time reading this one.
If you feel you have grabbed some bit of it then consider clapping this one.