DEV Community

Cover image for Flutter Hive: Mastering Offline Data Storage in Flutter
Gosu Code
Gosu Code

Posted on • Updated on

Flutter Hive: Mastering Offline Data Storage in Flutter

Introduction

Flutter Hive is not just a database; it's your app's secret weapon for storing data faster than you can say "hot reload." Hive is a lightweight, NoSQL database designed for Flutter, and it's here to make your offline experience smoother than ever.

Unleashing the Hive Magic

📦 Boxes for Everything:

Hive organizes data neatly into 'boxes.' Think of them as magical containers where your app's data resides, ready to be accessed at the speed of thought.

🔍 Query Like a Pro:

Searching for data? Hive's got your back. Its querying capabilities make finding information a breeze, ensuring you get what you need when you need it.

Flutter + Hive = 💙

When Flutter and Hive join forces, your app becomes an offline superstar. No more worries about lost connections or slow data access - Hive's got your back, keeping your app running smoothly, online or offline.

Let's Dive In!

Ready to embrace the speed, simplicity, and Flutter-friendliness of Hive? Buckle up as we dive into the world of Flutter Hive - your ticket to lightning-fast offline storage! 🚀

1. Installing dependencies
Add these dependencies on your pubspec.yaml

dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0

dev_dependencies:
  hive_generator: ^1.1.3
  build_runner: ^2.1.11
Enter fullscreen mode Exit fullscreen mode

Run the following command on your terminal to install dependencies.

flutter pub add hive hive_flutter hive_generator build_runner
Enter fullscreen mode Exit fullscreen mode

2. Initializing

main.dart

// Setting up Hive in Flutter
import 'package:hive/hive.dart';

void main() async {
  await Hive.initFlutter();
  // Hive is now ready to roll!
runApp(const MyApp());
}
Enter fullscreen mode Exit fullscreen mode

3. Create Model
person_model.dart

import 'package:hive/hive.dart';

part 'person_model.g.dart';

@HiveType(typeId: 1) //typeId should be unique for each model
class PersonModel {
  @HiveField(0) //uinque id for each field
  String name;

  @HiveField(1)
  int age;

  @HiveField(2)
  List<Person> friends;
}
Enter fullscreen mode Exit fullscreen mode

4. Generate TypeAdapter
After writing creating model, run the following command to generate TypeAdapter

dart run build_runner build
Enter fullscreen mode Exit fullscreen mode

Add the generated TypeAdapter to the main.dart file.

import 'package:hive/hive.dart';

void main() async {
  await Hive.initFlutter();
  Hive.registerAdapter(PersonModelAdapter()); //add TypeAdapater
runApp(const MyApp());
}
Enter fullscreen mode Exit fullscreen mode

5. Creating a CRUD service
Now we need to create some function to perform CRUD(create, read, update, delete) operation.

Let's create another file service.dart where we will keep our CRUD functions.

import 'package:your_app/models/person_model.dart';
import 'package:hive_flutter/hive_flutter.dart';

class Service {
final String  _boxName = "personBox";

Future<Box<PersonModel>> get _box async =>
      await Hive.openBox<PersonModel>(_boxName);

//create
  Future<void> addPerson(PersonModel personModel) async {
    var box = await _box;
    await box.add(personModel);
  }

//read
  Future<List<PersonModel>> getAllPerson() async {
    var box = await _box;
    return box.values.toList();
  }

//update
  Future<void> updateDeck(int index, PersonModel personModel) async { 
    var box = await _box;
    await box.putAt(index, personModel);
  }

//delete
  Future<void> deletePerson(int index) async {
    var box = await _box;
    await box.deleteAt(index);
  }
}
Enter fullscreen mode Exit fullscreen mode

Now we can use these function to perform CRUD operation.

6. Implementing

Adding to the box

final PersonService _personService = PersonService();
TextEditingController nameController = TextEditingController();
TextEditingController ageController = TextEditingController();

//create a function to add the data
 void saveAndPop(BuildContext context) async{
    Navigator.pop(context);
    String name = nameController.text.trim();
    int age = nameController.text
    var person = CardModel(person: name, age: age);
    await _personService.addPerson(person);           //writing
  }

..// rest of your code

Column(
          children: [
            TextField(
              controller: nameController,
              decoration: const InputDecoration(
                hintText: 'Name'
              ),
            ),
            TextField(
              controller: ageController,
              decoration: const InputDecoration(
                hintText: 'Age'
              ),
            ),
            ElevatedButton(onPressed: (){
              saveAndPop(context);
            }, child: Text("Add")),
            ElevatedButton(onPressed: (){
              Navigator.pop(context);
            }, child: Text("Cancel")),
          ],
        ),
Enter fullscreen mode Exit fullscreen mode

Getting from the box

//create an instance of the PersonService class.
final PersonService _personService = PersonService();

//open the box
Future<void> openBox() async {
  await Hive.openBox<PersonModel>('personBox');
}

@override
void initState() {    //calls when the widget is created
  super.initState();
  openBox();
}

@override
Widget build(BuildContext context) {
return Scaffold(
      body:
        //asynchronously build a widget tree
        FutureBuilder(
          future: _personService.getAllPerson(),
          builder: ( (context, snapshot) {
            if(snapshot.connectionState == ConnectionState.done){
              return 
           ValueListenableBuilder(
            //listens to changes in the hive box
            valueListenable: Hive.box<PersonModel>('personBox').listenable(), 
            builder: (context, box, _){
              //checking if the box is empty
              if(box.values.isEmpty){
              return const Center(
                child: Center(child: Text("No person available.")),
              );
              }
              //returns the data in list if there are any
              return ListView.builder(
                itemCount: box.values.length,
                itemBuilder: (context, index){
                  //retrieving PersonModel object from the box
                  var person = box.getAt(index);
                  return Column(
                           children: [
                              //displaying info
                              Text(person!.name),
                              Text(person!.age),
                              Text("Add Person"),
                            ],
                          );
                        }
                      );
                    });
                } else {
                 //if the future is not complete
                return Center(
                 child: CircularProgressIndicator()
              );
          }
      })
    )
  );
}
Enter fullscreen mode Exit fullscreen mode

Deleting from the box

IconButton(
       onPressed: (){
         _cardService.deleteCard(index);
         }, icon: Icon(
        Icons.delete, 
       ))
Enter fullscreen mode Exit fullscreen mode

Updating the values

final PersonService _personService = PersonService();

  TextEditingController nameController = TextEditingController();
  TextEditingController ageController = TextEditingController();

  //function to update
  void saveAndPop(BuildContext context) async{
    Navigator.pop(context);
    String name = nameController.text.trim();
    String age = ageController.text.trim();

    var card = PersonModel(name: name, age: age);
    await _personService.updatePerson(index,card);
  }

//Display the name and age before the change
  @override
  void initState(){
    super.initState();
    nameController.text = widget.name;
    ageController.text = widget.age;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
          children: [
            TextField(
              controller: nameController,
              decoration: const InputDecoration(
                hintText: 'Name'
              ),
            ),
            TextField(
              controller: ageController,
              decoration: const InputDecoration(
                hintText: 'Age'
              ),
            ),
            ElevatedButton(onPressed: (){
              saveAndPop(context);
            }, child: Text("Update")),
          ],
        ),
    );
  }
Enter fullscreen mode Exit fullscreen mode

Thank you for investing your time in understanding how Flutter Hive can transform your applications. If you found value in this blog or if there's anything you think I missed, please don't hesitate to drop your thoughts in the comments below. Your feedback is immensely valuable, and I encourage you to share your insights, ask questions, or point out any mistakes you may have notices.

Top comments (0)