Flutter Hive: Mastering Offline Data Storage in Flutter
Tags: flutter, tutorial, database, mobile
Published: 2024-02-04 06:08:15

## 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
```


> Run the following command on your terminal to install dependencies.

```
flutter pub add hive hive_flutter hive_generator build_runner
```


**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());
}
```


**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;
}
```
**4. Generate TypeAdapter**
After writing creating model, run the following command to generate **TypeAdapter**

```
dart run build_runner build
```
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());
}
```

**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);
  }
}
```
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")),
          ],
        ),
```

> 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()
              );
          }
      })
    )
  );
}
```

> Deleting from the box

```
IconButton(
       onPressed: (){
         _cardService.deleteCard(index);
         }, icon: Icon(
        Icons.delete, 
       ))
```

> 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")),
          ],
        ),
    );
  }
```
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.