Hive

FlutterDartlocal databasekey-valuelightweightNoSQLmobile

Cache Library

Hive

Overview

Hive is a lightweight and fast key-value database written in pure Dart. Implemented entirely in Dart, it's optimized as a local data storage solution for Flutter applications. As an alternative to heavy databases like SQLite, it provides a simple API and high performance, working across iOS, Android, desktop, and web platforms.

Details

Hive is a NoSQL database designed for lightweight data persistence in mobile applications. It supports transactions, type safety, and CRUD operations while requiring minimal configuration. Internally, it stores data in binary format to achieve fast read and write performance.

Key Features

  • Pure Dart Implementation: Cross-platform support without external dependencies
  • High Performance: Fast data access through binary format storage
  • Type Safety: Type-safe data operations through generic support
  • Transactions: write/read transactions ensuring atomicity
  • Auto Key Generation: Automatic increment keys when used in list format
  • Custom Object Support: Storage of complex data structures through serialization
  • Lightweight: Minimal memory footprint and disk usage

Architecture

  • Box: Container for storing data (equivalent to tables)
  • Adapter: Serialization/deserialization for custom objects
  • Transaction: Transaction control through write() and read()
  • Type Safety: Type constraints through generics (Box<T>)

Pros and Cons

Pros

  • Simplicity: Immediate usage with minimal configuration
  • High Performance: Faster read/write performance than SQLite
  • Type Safety: Bug reduction through compile-time type checking
  • Lightweight: Minimal impact on app size
  • Cross-Platform: Available on all Flutter-supported platforms
  • Offline Support: Data persistence without network connectivity

Cons

  • No Complex Queries: Lacks advanced query features like SQL
  • No Relational Data: No relational database functionality
  • Limited Concurrent Access: Multi-process concurrent access is discouraged
  • Not Suitable for Large Data: May not be suitable for large amounts of data

Reference Links

Code Examples

Basic Setup and Box Operations

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Initialize Hive
  final directory = await getApplicationDocumentsDirectory();
  Hive.defaultDirectory = directory.path;
  
  runApp(MyApp());
}

// Basic data operations
void basicOperations() {
  // Open default Box
  final box = Hive.box();
  
  // Store data
  box.put('name', 'Alice');
  box.put('age', 25);
  box.put('city', 'Tokyo');
  
  // Retrieve data
  final name = box.get('name');
  final age = box.get('age', defaultValue: 0);
  
  print('Name: $name, Age: $age');
  
  // Map-style operations
  box['email'] = '[email protected]';
  final email = box['email'];
  
  // Bulk data storage
  box.putAll({
    'country': 'Japan',
    'language': 'Japanese'
  });
}

Named Boxes and Type Safety

// Named Box creation
void namedBoxExample() {
  final settingsBox = Hive.box(name: 'settings');
  final cacheBox = Hive.box(name: 'cache');
  
  // Store settings data
  settingsBox.put('theme', 'dark');
  settingsBox.put('notifications', true);
  
  // Store cache data
  cacheBox.put('lastUpdate', DateTime.now().toIso8601String());
}

// Type-safe Box
void typeSafeExample() {
  // Box that stores only String types
  final Box<String> stringBox = Hive.box<String>(name: 'strings');
  
  stringBox.put('greeting', 'Hello, World!');
  stringBox.put('farewell', 'Goodbye!');
  
  // Compile-time error
  // stringBox.put('number', 123); // Error!
  
  // Safe retrieval
  final greeting = stringBox.get('greeting') ?? 'Default';
}

List-style Data Operations

void listLikeOperations() {
  final box = Hive.box();
  
  // Add data in list format
  box.add('First item');
  box.add('Second item');
  box.add('Third item');
  
  // Retrieve by index
  print(box.getAt(0)); // First item
  print(box.getAt(1)); // Second item
  
  // Can be mixed with map format
  box.put('key1', 'Value by key');
  
  print(box.getAt(3)); // Value by key
  
  // Update by index
  box[0] = 'Updated first item';
  
  // Delete data
  box.deleteAt(1); // Delete Second item
}

Storing Custom Objects

// Custom class definition
class User {
  User({required this.name, required this.email, required this.age});
  
  // Factory constructor from JSON
  factory User.fromJson(Map<String, dynamic> json) => User(
    name: json['name'] as String,
    email: json['email'] as String,
    age: json['age'] as int,
  );
  
  final String name;
  final String email;
  final int age;
  
  // Convert to JSON
  Map<String, dynamic> toJson() => {
    'name': name,
    'email': email,
    'age': age,
  };
  
  @override
  String toString() => '$name ($email) - $age years old';
}

void customObjectExample() {
  // Register adapter
  Hive.registerAdapter('User', User.fromJson);
  
  final box = Hive.box();
  
  // Store custom object
  final user = User(
    name: 'Bob',
    email: '[email protected]',
    age: 30,
  );
  
  box.put('currentUser', user);
  
  // Retrieve custom object
  final retrievedUser = box.get('currentUser') as User?;
  print('Retrieved user: $retrievedUser');
}

Transaction Processing

void transactionExample() {
  final box = Hive.box();
  
  // Write transaction
  box.write(() {
    box.put('account1', 1000);
    box.put('account2', 500);
    box.put('account3', 750);
  });
  
  // Read transaction
  box.read(() {
    final total = (box.get('account1', defaultValue: 0) as int) +
                  (box.get('account2', defaultValue: 0) as int) +
                  (box.get('account3', defaultValue: 0) as int);
    print('Total balance: $total');
  });
  
  // Atomicity example (rollback on error)
  box.put('balance', 1000);
  
  try {
    box.write(() {
      box.put('balance', 500);
      throw Exception('Some error occurred');
    });
  } catch (e) {
    print('Error occurred: $e');
  }
  
  print('Balance: ${box.get('balance')}'); // 1000 (rolled back)
}

Hive Usage in Flutter App

class TodoApp extends StatefulWidget {
  @override
  _TodoAppState createState() => _TodoAppState();
}

class _TodoAppState extends State<TodoApp> {
  final Box<String> todoBox = Hive.box<String>('todos');
  final TextEditingController _controller = TextEditingController();
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Hive Todo App')),
      body: Column(
        children: [
          // Add new TODO
          Padding(
            padding: EdgeInsets.all(16.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    decoration: InputDecoration(
                      hintText: 'Enter TODO',
                    ),
                  ),
                ),
                IconButton(
                  icon: Icon(Icons.add),
                  onPressed: () {
                    if (_controller.text.isNotEmpty) {
                      setState(() {
                        todoBox.add(_controller.text);
                        _controller.clear();
                      });
                    }
                  },
                ),
              ],
            ),
          ),
          
          // Display TODO list
          Expanded(
            child: ListView.builder(
              itemCount: todoBox.length,
              itemBuilder: (context, index) {
                final todo = todoBox.getAt(index);
                return ListTile(
                  title: Text(todo ?? ''),
                  trailing: IconButton(
                    icon: Icon(Icons.delete),
                    onPressed: () {
                      setState(() {
                        todoBox.deleteAt(index);
                      });
                    },
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

Asynchronous Processing and Isolates

import 'dart:isolate';

void isolateExample() async {
  final box = Hive.box();
  
  // Store data in main thread
  box.put('message', 'Hello from main');
  
  // Perform Hive operation in different isolate
  await Hive.compute(() {
    // Access same Box from other isolate
    final box = Hive.box();
    print(box.get('message')); // Hello from main
    
    // Update data
    box.put('message', 'Updated from isolate');
  });
  
  // Check in main thread
  print(box.get('message')); // Updated from isolate
}

Data Cleanup and Maintenance

void maintenanceOperations() {
  final box = Hive.box();
  
  // Delete specific key
  box.delete('oldKey');
  
  // Delete multiple keys
  box.deleteAll(['key1', 'key2', 'key3']);
  
  // Clear all data
  box.clear();
  
  // Check Box size
  print('Box size: ${box.length}');
  print('Box is empty: ${box.isEmpty}');
  
  // Get all keys
  final keys = box.keys.toList();
  print('All keys: $keys');
  
  // Get all values
  final values = box.values.toList();
  print('All values: $values');
}