In this Flutter tutorial, we’ll show you how to use Hive – a fast and lightweight NoSQL database solution – to store and manage data in your Flutter app. You’ll learn how to set up Hive in your project, create and manage a Hive box, and perform CRUD (Create, Read, Update, Delete) operations on your data. We’ll provide step-by-step instructions and code examples so you can follow along and implement Hive in your own app.
Table of Contents:
Introduction to Hive database
Setting up the project with Hive
Creating and opening a Hive box
Defining and using Hive adapters
Adding and retrieving data from the Hive box
Updating and deleting data in the Hive box
Conclusion and further resources
Introduction:
In this section, we’ll introduce Hive and explain why it’s a good choice for managing data in Flutter apps. We’ll cover the basics of NoSQL databases, and explain how Hive differs from other popular database solutions.
Setting up the project:
Here, we’ll show you how to set up a new Flutter project with the necessary dependencies for using Hive. We’ll cover how to install and configure the hive_flutter and path packages, and how to import them into your project.
name: flutter_hive_database
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: '>=2.18.6 <3.0.0'
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
intl:
# add this two dependency
hive:
hive_flutter:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
# add this 2 depe.....
hive_generator:
build_runner:
flutter:
uses-material-design: true
DartCreating and opening a Hive box:
In this section, we’ll create a new Hive box to store our data. We’ll cover how to define a Hive adapter for our data model, how to initialize the Hive box, and how to close the box when we’re done.
//import thos packages
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
void main()async {
WidgetsFlutterBinding.ensureInitialized();
//init hive
await Hive.initFlutter();
Hive.registerAdapter(TransactionAdapter());
//name of box
await Hive.openBox<Transaction>('transactions');
runApp(const MyApp());
}
DartCreate model class
import 'package:hive/hive.dart';
//create part
part 'Transaction.g.dart';
@HiveType(typeId: 0)
class Transaction extends HiveObject{
@HiveField(0)
late String name;
@HiveField(1)
late DateTime createDate;
@HiveField(2)
late bool isExpense=true;
@HiveField(3)
late double amount;
}
/*
Some Changes need in this model
1)Modify Model class
2)Generate Model Adapter
3)Register Model Adapter
*/
DartIn Terminal type this command
flutter packages pub run build_runner build
Adding and retrieving data from the Hive box:
Now that we have a Hive box set up, we can start adding data to it. We’ll show you how to use Hive to add data to the box, retrieve it by key, and retrieve all the data in the box.
Future addTransaction(String name, double amount, bool isExpense) async {
//create hive transaction object
final transaction = Transaction()
..name = name
..createDate = DateTime.now()
..amount = amount
..isExpense = isExpense;
final box = Boxes.getTransactions();
box.add(transaction);
//box.put('mykey', transaction);
// final mybox = Boxes.getTransactions();
// final myTransaction = mybox.get('key');
// mybox.values;
// mybox.keys;
}
Dart@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text('Hive Expense Tracker'),
centerTitle: true,
),
//get value from hive using listerner
body: ValueListenableBuilder<Box<Transaction>>(
valueListenable: Boxes.getTransactions().listenable(),
builder: (context, box, _) {
final transactions = box.values.toList().cast<Transaction>();
return buildContent(transactions);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => showDialog(
context: context,
builder: (context) => TransactionDialog(
onClickedDone: addTransaction,
),
),
),
);
DartUpdating and deleting data in the Hive box:
Finally, we’ll cover how to perform CRUD operations on the data in the Hive box. We’ll show you how to update and delete data, and how to handle errors and exceptions that may occur during these operations.
void editTransaction(
Transaction transaction,
String name,
double amount,
bool isExpense,
) {
transaction.name = name;
transaction.amount = amount;
transaction.isExpense = isExpense;
// final box = Boxes.getTransactions();
// box.put(transaction.key, transaction);
transaction.save();
}
void deleteTransaction(Transaction transaction) {
// final box = Boxes.getTransactions();
// box.delete(transaction.key);
transaction.delete();
//setState(() => transactions.remove(transaction));
}
Dartfull Code:
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_hive_database/model/Transaction.dart';
import 'package:flutter_hive_database/page/transactions_page.dart';
//import thos packages
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
void main()async {
WidgetsFlutterBinding.ensureInitialized();
//init hive
await Hive.initFlutter();
Hive.registerAdapter(TransactionAdapter());
//name of box
await Hive.openBox<Transaction>('transactions');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TransactionPage()
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
],
),
),
);
}
}
Dartboxes.dart
import 'package:hive/hive.dart';
import 'model/Transaction.dart';
class Boxes {
static Box<Transaction> getTransactions() =>
Hive.box<Transaction>('transactions');
}
DartTransaction.dart as Model class
import 'package:hive/hive.dart';
//create part
part 'Transaction.g.dart';
@HiveType(typeId: 0)
class Transaction extends HiveObject{
@HiveField(0)
late String name;
@HiveField(1)
late DateTime createDate;
@HiveField(2)
late bool isExpense=true;
@HiveField(3)
late double amount;
}
/*
Some Changes need in this model
1)Modify Model class
2)Generate Model Adapter
3)Register Model Adapter
*/
Darttransaction_dialog.dart
import 'package:flutter/material.dart';
import '../model/Transaction.dart';
class TransactionDialog extends StatefulWidget {
final Transaction? transaction;
final Function(String name, double amount, bool isExpense) onClickedDone;
const TransactionDialog({
Key? key,
this.transaction,
required this.onClickedDone,
}) : super(key: key);
@override
_TransactionDialogState createState() => _TransactionDialogState();
}
class _TransactionDialogState extends State<TransactionDialog> {
final formKey = GlobalKey<FormState>();
final nameController = TextEditingController();
final amountController = TextEditingController();
bool isExpense = true;
@override
void initState() {
super.initState();
if (widget.transaction != null) {
final transaction = widget.transaction!;
nameController.text = transaction.name;
amountController.text = transaction.amount.toString();
isExpense = transaction.isExpense;
}
}
@override
void dispose() {
nameController.dispose();
amountController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final isEditing = widget.transaction != null;
final title = isEditing ? 'Edit Transaction' : 'Add Transaction';
return AlertDialog(
title: Text(title),
content: Form(
key: formKey,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(height: 8),
buildName(),
SizedBox(height: 8),
buildAmount(),
SizedBox(height: 8),
buildRadioButtons(),
],
),
),
),
actions: <Widget>[
buildCancelButton(context),
buildAddButton(context, isEditing: isEditing),
],
);
}
Widget buildName() => TextFormField(
controller: nameController,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter Name',
),
validator: (name) =>
name != null && name.isEmpty ? 'Enter a name' : null,
);
Widget buildAmount() => TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter Amount',
),
keyboardType: TextInputType.number,
validator: (amount) => amount != null && double.tryParse(amount) == null
? 'Enter a valid number'
: null,
controller: amountController,
);
Widget buildRadioButtons() => Column(
children: [
RadioListTile<bool>(
title: Text('Expense'),
value: true,
groupValue: isExpense,
onChanged: (value) => setState(() => isExpense = value!),
),
RadioListTile<bool>(
title: Text('Income'),
value: false,
groupValue: isExpense,
onChanged: (value) => setState(() => isExpense = value!),
),
],
);
Widget buildCancelButton(BuildContext context) => TextButton(
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
);
Widget buildAddButton(BuildContext context, {required bool isEditing}) {
final text = isEditing ? 'Save' : 'Add';
return TextButton(
child: Text(text),
onPressed: () async {
final isValid = formKey.currentState!.validate();
if (isValid) {
final name = nameController.text;
final amount = double.tryParse(amountController.text) ?? 0;
widget.onClickedDone(name, amount, isExpense);
Navigator.of(context).pop();
}
},
);
}
}
DartTransaction_page.dart
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:intl/intl.dart';
import '../boxes.dart';
import '../model/Transaction.dart';
import '../widget/transaction_dialog.dart';
class TransactionPage extends StatefulWidget {
@override
_TransactionPageState createState() => _TransactionPageState();
}
class _TransactionPageState extends State<TransactionPage> {
@override
void dispose() {
//close hive
Hive.close();
super.dispose();
}
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text('Hive Expense Tracker'),
centerTitle: true,
),
//get value from hive using listerner
body: ValueListenableBuilder<Box<Transaction>>(
valueListenable: Boxes.getTransactions().listenable(),
builder: (context, box, _) {
final transactions = box.values.toList().cast<Transaction>();
return buildContent(transactions);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => showDialog(
context: context,
builder: (context) => TransactionDialog(
onClickedDone: addTransaction,
),
),
),
);
Widget buildContent(List<Transaction> transactions) {
if (transactions.isEmpty) {
return Center(
child: Text(
'No expenses yet!',
style: TextStyle(fontSize: 24),
),
);
} else {
final netExpense = transactions.fold<double>(
0,
(previousValue, transaction) => transaction.isExpense
? previousValue - transaction.amount
: previousValue + transaction.amount,
);
final newExpenseString = '\$${netExpense.toStringAsFixed(2)}';
final color = netExpense > 0 ? Colors.green : Colors.red;
return Column(
children: [
SizedBox(height: 24),
Text(
'Net Expense: $newExpenseString',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: color,
),
),
SizedBox(height: 24),
Expanded(
child: ListView.builder(
padding: EdgeInsets.all(8),
itemCount: transactions.length,
itemBuilder: (BuildContext context, int index) {
final transaction = transactions[index];
return buildTransaction(context, transaction);
},
),
),
],
);
}
}
Widget buildTransaction(
BuildContext context,
Transaction transaction,
) {
final color = transaction.isExpense ? Colors.red : Colors.green;
final date = DateFormat.yMMMd().format(transaction.createDate);
final amount = '\$' + transaction.amount.toStringAsFixed(2);
return Card(
color: Colors.white,
child: ExpansionTile(
tilePadding: EdgeInsets.symmetric(horizontal: 24, vertical: 8),
title: Text(
transaction.name,
maxLines: 2,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
subtitle: Text(date),
trailing: Text(
amount,
style: TextStyle(
color: color, fontWeight: FontWeight.bold, fontSize: 16),
),
children: [
buildButtons(context, transaction),
],
),
);
}
Widget buildButtons(BuildContext context, Transaction transaction) => Row(
children: [
Expanded(
child: TextButton.icon(
label: Text('Edit'),
icon: Icon(Icons.edit),
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => TransactionDialog(
transaction: transaction,
onClickedDone: (name, amount, isExpense) =>
editTransaction(transaction, name, amount, isExpense),
),
),
),
),
),
Expanded(
child: TextButton.icon(
label: Text('Delete'),
icon: Icon(Icons.delete),
onPressed: () => deleteTransaction(transaction),
),
)
],
);
//lets check and add data
Future addTransaction(String name, double amount, bool isExpense) async {
//create hive transaction object
final transaction = Transaction()
..name = name
..createDate = DateTime.now()
..amount = amount
..isExpense = isExpense;
final box = Boxes.getTransactions();
box.add(transaction);
//box.put('mykey', transaction);
// final mybox = Boxes.getTransactions();
// final myTransaction = mybox.get('key');
// mybox.values;
// mybox.keys;
}
void editTransaction(
Transaction transaction,
String name,
double amount,
bool isExpense,
) {
transaction.name = name;
transaction.amount = amount;
transaction.isExpense = isExpense;
// final box = Boxes.getTransactions();
// box.put(transaction.key, transaction);
transaction.save();
}
void deleteTransaction(Transaction transaction) {
// final box = Boxes.getTransactions();
// box.delete(transaction.key);
transaction.delete();
//setState(() => transactions.remove(transaction));
}
}
DartConclusion and further resources:
In this section, we’ll summarize what we’ve covered in this tutorial and suggest some further resources for learning more about Hive and NoSQL databases in general. We’ll also encourage viewers to try implementing Hive in their own Flutter projects and share their results with us.
By the end of this tutorial, you’ll have a solid understanding of how to use Hive in your Flutter app to store and manage data. You’ll be able to create a Hive box, define adapters for your data models, add and retrieve data from the box, and perform CRUD operations on your data. Whether you’re building an Android, iOS, or web app with Flutter, Hive can be a valuable tool for managing your data.