Flutter : Store your Local Data with Hive

Flutter Hive
Local Storage is vital for mobile app development. Nowadays, many super apps use local storage to implement Offline-first App. So user still can open the app, watch and check their latest data even when their device on offline condition. Local storage have many benefits:
- Offline Functionality : When device no connect to internet, user still can use the app and watch their stored data like profile, flag, instagram feed, x timeline, stories, history, etc
- Reduce Server Load : By Storing the data, app doesn't need to fetch API when there is no updated data
- Data Management : Apps can do manipulation, processing, calculation and etc some data that not provided by the API
- Speed and Responsive : Read data from local database is faster than API because it doesn't need internet connection
Hive is one of many Library and Package to store local data for flutter that lightweight and fast NoSQL database. Hive works based on key-value pairs, similar to dictionaries. You define a unique key for each piece of data, and Hive associates it with the actual value. Hive is known for its speedy performance and uses binary storage, making it ideal for frequently accessed data and highly efficient.
Hive Dependency
pubspec.yaml
dependencies:
hive: ^2.2.3
hive_flutter: ^1.1.0
dev_dependencies:
build_runner: ^2.4.14
hive_generator: ^2.0.1
However, since the Hive package has not seen updates in over two years, you can also use the community edition (Hive CE).
dependencies:
hive_ce: ^2.9.0
hive_ce_flutter: ^2.2.0
dev_dependencies:
build_runner: ^2.4.14
hive_ce_generator: ^1.8.2
Initialize
lib/main.dart
import 'package:hive_flutter/hive_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// initialize Hive for flutter
await Hive.initFlutter();
runApp(const MyApp());
}
Entity
Let's create some class for entity or model.
- Add
@HiveType()
annotation on top of class to define this class as Hive class. - Add
@HiveField()
annotation to specify Hive key for each field of data and properties. - Use supported data types like String, int, bool, DateTime, List, or Map
- Every field must have unique key and index like
@HiveField(0)
lib/entity/user.dart
import 'package:hive/hive.dart';
part 'user.g.dart';
@HiveType(typeId: 1)
class User {
@HiveField(0)
final String name;
@HiveField(1)
final int age;
@HiveField(2)
final DateTime createdAt;
User({required this.name, required this.age, required this.createdAt});
}
Type Adapter
If your data model includes a non-supported type like a custom class, you need to define a Type Adapter. use this code below in terminal to run build generator and generate TypeAdapter for the entity.
dart run build_runner build --delete-conflicting-outputs
Register the builded Type adapter to lib/main.dart
.
import 'package:hive_flutter/hive_flutter.dart';
import 'entity/user.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
// register the type adapter
Hive.registerAdapter(UserAdapter());
runApp(const MyApp());
}
Hive Box
Create Box of Hive for each of Entity that you created.
You can set the Box inside lib/main.dart
, Screen Class or your Data package if you use Clean Architecture.
for Example in lib/main.dart
void main() async {
...
var boxUser = await Hive.openBox<User>('userBox');
runApp(const MyApp());
}
Closing Hive Box When your app is closing or no longer needs the Hive box.
await boxUser.close();
CRUD Operation
- Create
boxUser.add(User(name: "Modtion", age: 28, createdAt: DateTime.now()));
boxUser.addAll(
[
User(name: "Modtion", age: 28, createdAt: DateTime.now()),
User(name: "Modtion", age: 28, createdAt: DateTime.now()),
]);
- Read
var data = boxUser.getAt(0); // index
var list = boxUser.values.toList() as List<User>;
- Update
boxUser.putAt(0, User(name: "Modtion", age: 28, createdAt: DateTime.now())); // index
- Delete
boxUser.deleteAt(0); // index
boxUser.deleteAll();
- Clear
boxUser.clear();
Example
I'll show you some simple code to use basic of Hive in flutter.
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'boxes.dart';
import 'entity/user.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(UserAdapter());
boxUser = await Hive.openBox<User>('userBox');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void addUser() {
boxUser.add(User(name: "Modtion", age: 28, createdAt: DateTime.now()));
setState(() {});
}
void deleteUser(int index) {
boxUser.deleteAt(index);
setState(() {});
}
void clearUser() {
boxUser.clear();
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: boxUser.length,
itemBuilder: (context, index) {
User task = boxUser.getAt(index);
return ListTile(
title: Text(task.name),
subtitle: Text(task.createdAt.toString()),
trailing: Text("age: ${task.age}"),
leading: IconButton(
onPressed: () {
deleteUser(index);
},
icon: const Icon(Icons.remove)),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: addUser,
child: const Icon(Icons.add),
),
);
}
}
Example 2
If you want to setup all hive method in a class file like HiveService, you can do like this.
import 'package:hive_flutter/hive_flutter.dart';
import 'entity/user.dart';
class HiveService {
final String _boxName = 'userBox';
Future<Box> get _box async => await Hive.openBox<User>(_boxName);
Future<void> create(User user) async {
var box = await _box;
box.add(user);
}
Future<List<User>> read() async {
var box = await _box;
return box.values.toList() as List<User>;
}
Future<void> update(int index, User user) async {
var box = await _box;
box.put(index, user);
}
Future<void> delete(int index) async {
var box = await _box;
box.deleteAt(index);
}
Future<void> clear() async {
var box = await _box;
box.clear();
}
}