DEV Community

Cover image for Flutter:Hive With Api
Vikraman
Vikraman

Posted on • Edited on

Flutter:Hive With Api

Introduction

  • Hive is a lightweight and fast NoSQL database that can be used to store data in Flutter applications.
  • In this blog, we will explore how to fetch data from APi, store and use it in Hive in Flutter.
  • This Blog includes defining Hive type adapters, storing and reading from Hive.
  • By using Hive in our Flutter applications, we can easily store and retrieve data without the overhead of traditional SQL databases.
  • It is mostly used for offline support for the application.

Boxes

Hive uses Boxes to store data. All data in Hive is organized into boxes. A box is similar to a table in SQL, but it lacks structure and can contain any data.We can store an integer, string, list of strings, Boolean, double, etc. in Hive.

To manipulate the Box, we have to open it first.

OpenBox

Open a Hive box in your app to store your data:

var box = await Hive.openBox<Data>('dataBox');
Enter fullscreen mode Exit fullscreen mode

The depicts that the box belongs to a specific type.

Read Box

To read an already opened box:

var box = Hive.box('dataBox');
Enter fullscreen mode Exit fullscreen mode

Close Box

If you don't need a box again, close it. All the data in the box will be removed from memory, and the box file will be closed once all active operations have completed.

var box = await Hive.openBox('dataBox');
await box.put('hello 'world');
await box.close();
Enter fullscreen mode Exit fullscreen mode

Operations

The Box has the below operations which is used mostly:

Read
var box = Hive.box('dataBox');
String name = box.get('name');
Enter fullscreen mode Exit fullscreen mode
Write
var box = Hive.box('dataBox');
box.put('name', 'Paul');
Enter fullscreen mode Exit fullscreen mode
Delete
var box = await Hive.openBox('dataBox');
await box.put('key1', 'value1');
await box.delete('key1');
Enter fullscreen mode Exit fullscreen mode
Clear
var box = await Hive.openBox('dataBox');
await box.clear();
Enter fullscreen mode Exit fullscreen mode

Hive box

TypeAdapters:

If you want to store objects, you must register a TypeAdapter that converts them both to and from binary form.

We can either write or generate a TypeAdapter. Most of the time, the generated adapter works exceptionally well. A manually written adapter can sometimes be used to improve minor details.

Generate Adapter

The hive_generator package can generate TypeAdapters for nearly any class.

  • To generate a type adapter for a class, give it with @HiveType and provide a typeId (between 0 and 223)
  • All fields that should be saved with @HiveField.
import 'package:hive/hive.dart';

part 'data.g.dart';

@HiveType(typeId: 1)
class Data {
  @HiveField(0)
  String name;

  @HiveField(1)
  String id;

  Data({required this.name, required this.id});
}
Enter fullscreen mode Exit fullscreen mode
  • After this, open terminal and run the command dart run build_runner build
  • To use this type adapter, first generate the adapter.

Let’s start the application.

Simple Data List

Let’s first add the dependencies:
pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  hive: ^2.2.3
  hive_flutter: ^1.1.0
  http: ^0.13.6

dev_dependencies:
  flutter_test:
    sdk: flutter
  hive_generator: ^2.0.1
  build_runner: ^2.4.9

Enter fullscreen mode Exit fullscreen mode

Once the dependencies are added, run flutter pub.get
Then add the import statements.

import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
Enter fullscreen mode Exit fullscreen mode

data.dart

  • Generate the needed adapter.
  • Note that the name used for the file should be used in statement which will generate the adapter
import 'package:hive/hive.dart';

part 'data.g.dart';  // Statement which will generate the adapter

@HiveType(typeId: 1)
class Data {
  @HiveField(0)
  String name;

  @HiveField(1)
  String id;

  Data({required this.name, required this.id});
}

Enter fullscreen mode Exit fullscreen mode
  • Now run the command dart run build_runner build.
  • This will create the required TypeAdapter. As we generate the TypeAdapter, let’s register the adapter in the main.dart.
import 'data.dart';

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

Enter fullscreen mode Exit fullscreen mode

api.dart
Once the adapter has been registered, let’s create a simple get request from the mock Api endpoint.

If you want to create a mockApi, please visit

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:hive/hive.dart';

import 'data.dart';

class ApiService {
  static const String _baseUrl = 'https://66443e296c6a656587099b9d.mockapi.io/person/data1'; // change it with your GET api

  static Future<void> fetchDataAndStoreInHive() async {
    final response = await http.get(Uri.parse('$_baseUrl'));
    if (response.statusCode == 200) {
      final List<dynamic> responseData = jsonDecode(response.body);
      print(responseData);
      final box = await Hive.openBox('myData');
      await box.clear();
      responseData.forEach((data) {
        box.add(Data(id: data['id'], name: data['name']));
      });
    } else {
      throw Exception('Failed to load data');
    }
  }
}

Enter fullscreen mode Exit fullscreen mode
  • Once the response has been parsed using jsonDecode, it will be stored as responseData.
  • Then we open the Hive box and clear it for if any existing data is available.
  • Then we add the data from response data into the box with keys as “id” and “name”.

main.dart
Once the data has been stored in the box, we use it in the main.dart to list the data in the box.

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

import 'api.dart';
import 'data.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Data app',
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSwatch(accentColor: Colors.blue),
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Hive with API),
      ),
      body: FutureBuilder(
        future: Hive.openBox('myData'),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            if (snapshot.hasError) {
              return Center(
                child: Text('Error'),
              );
            } else {
              final myDataBox = Hive.box('myData');
              return ListView.builder(
                itemCount: myDataBox.length,
                itemBuilder: (context, index) {
                  final myData = myDataBox.getAt(index) as Data;
                  return Card(
                    child: ListTile(
                      title: Text(myData.name),
                      subtitle: Text('ID: ${myData.id}'),
                    ),
                  );
                },
              );
            }
          } else {
            return Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          await ApiService.fetchDataAndStoreInHive();
        },
        child: Icon(Icons.refresh),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Here we open the box and assign it to the future of the futureBuilder.
  • Then we get the data along with its index and display the name and id of each individual object stored.
  • For additional measures, if the data changes overtime we can use the floating action button to get the data from the api and overwrite the existing data.
  • Now even if you stop the server or offline the data will still be available as the data is still stored in the local storage

Hope this has helped!

Top comments (0)