Hive is a lightweight and fast key-value database written in pure Dart. It is a great choice for Flutter applications that need a simple and efficient way to store data locally. In this section, we will cover the basics of using Hive for local storage in Flutter.

Key Concepts

  1. Boxes: The main storage unit in Hive. A box can be thought of as a collection of key-value pairs.
  2. Adapters: Custom serializers for complex data types.
  3. TypeId: A unique identifier for each adapter.

Setting Up Hive

Step 1: Add Dependencies

First, add the Hive and Hive Flutter dependencies to your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  hive: ^2.0.0
  hive_flutter: ^1.0.0

dev_dependencies:
  hive_generator: ^1.0.0
  build_runner: ^2.0.0

Step 2: Initialize Hive

Initialize Hive in the main.dart file:

import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';

void main() async {
  await Hive.initFlutter();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen(),
    );
  }
}

Step 3: Open a Box

Open a box to store data:

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  Box box;

  @override
  void initState() {
    super.initState();
    openBox();
  }

  void openBox() async {
    box = await Hive.openBox('myBox');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Hive Example'),
      ),
      body: Center(
        child: Text('Hive Local Storage'),
      ),
    );
  }
}

Storing and Retrieving Data

Storing Data

To store data in a box, use the put method:

void storeData() {
  box.put('name', 'John Doe');
}

Retrieving Data

To retrieve data from a box, use the get method:

void retrieveData() {
  String name = box.get('name');
  print(name); // Output: John Doe
}

Using Adapters for Custom Data Types

Step 1: Define a Model

Define a model class and annotate it with HiveType and HiveField:

import 'package:hive/hive.dart';

part 'person.g.dart';

@HiveType(typeId: 0)
class Person {
  @HiveField(0)
  final String name;

  @HiveField(1)
  final int age;

  Person(this.name, this.age);
}

Step 2: Generate the Adapter

Run the build runner to generate the adapter:

flutter packages pub run build_runner build

Step 3: Register the Adapter

Register the adapter in the main.dart file:

import 'package:hive/hive.dart';
import 'person.dart';

void main() async {
  await Hive.initFlutter();
  Hive.registerAdapter(PersonAdapter());
  runApp(MyApp());
}

Step 4: Store and Retrieve Custom Data

Store and retrieve custom data types:

void storeCustomData() {
  var person = Person('John Doe', 30);
  box.put('person', person);
}

void retrieveCustomData() {
  Person person = box.get('person');
  print('${person.name}, ${person.age}'); // Output: John Doe, 30
}

Practical Exercise

Exercise

  1. Create a Flutter app that uses Hive to store a list of tasks.
  2. Each task should have a title and a description.
  3. Implement functionality to add, retrieve, and delete tasks.

Solution

import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';

part 'task.g.dart';

@HiveType(typeId: 1)
class Task {
  @HiveField(0)
  final String title;

  @HiveField(1)
  final String description;

  Task(this.title, this.description);
}

void main() async {
  await Hive.initFlutter();
  Hive.registerAdapter(TaskAdapter());
  await Hive.openBox<Task>('tasks');
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: TaskScreen(),
    );
  }
}

class TaskScreen extends StatefulWidget {
  @override
  _TaskScreenState createState() => _TaskScreenState();
}

class _TaskScreenState extends State<TaskScreen> {
  final Box<Task> taskBox = Hive.box<Task>('tasks');
  final TextEditingController titleController = TextEditingController();
  final TextEditingController descriptionController = TextEditingController();

  void addTask() {
    final String title = titleController.text;
    final String description = descriptionController.text;

    if (title.isNotEmpty && description.isNotEmpty) {
      final task = Task(title, description);
      taskBox.add(task);
      titleController.clear();
      descriptionController.clear();
    }
  }

  void deleteTask(int index) {
    taskBox.deleteAt(index);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Hive Task Manager'),
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: titleController,
              decoration: InputDecoration(labelText: 'Title'),
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: descriptionController,
              decoration: InputDecoration(labelText: 'Description'),
            ),
          ),
          ElevatedButton(
            onPressed: addTask,
            child: Text('Add Task'),
          ),
          Expanded(
            child: ValueListenableBuilder(
              valueListenable: taskBox.listenable(),
              builder: (context, Box<Task> box, _) {
                if (box.values.isEmpty) {
                  return Center(
                    child: Text('No tasks added yet!'),
                  );
                }

                return ListView.builder(
                  itemCount: box.length,
                  itemBuilder: (context, index) {
                    final task = box.getAt(index);
                    return ListTile(
                      title: Text(task.title),
                      subtitle: Text(task.description),
                      trailing: IconButton(
                        icon: Icon(Icons.delete),
                        onPressed: () => deleteTask(index),
                      ),
                    );
                  },
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

Conclusion

In this section, we covered the basics of using Hive for local storage in Flutter. We learned how to set up Hive, store and retrieve data, and use adapters for custom data types. We also implemented a practical exercise to reinforce the concepts. Hive is a powerful and efficient solution for local storage in Flutter applications, and mastering it will greatly enhance your app's data management capabilities.

Flutter Development Course

Module 1: Introduction to Flutter

Module 2: Dart Programming Basics

Module 3: Flutter Widgets

Module 4: State Management

Module 5: Navigation and Routing

Module 6: Networking and APIs

Module 7: Persistence and Storage

Module 8: Advanced Flutter Concepts

Module 9: Testing and Debugging

Module 10: Deployment and Maintenance

Module 11: Flutter for Web and Desktop

© Copyright 2024. All rights reserved