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');
The depicts that the box belongs to a specific type.
Read Box
To read an already opened box:
var box = Hive.box('dataBox');
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();
Operations
The Box has the below operations which is used mostly:
Read
var box = Hive.box('dataBox');
String name = box.get('name');
Write
var box = Hive.box('dataBox');
box.put('name', 'Paul');
Delete
var box = await Hive.openBox('dataBox');
await box.put('key1', 'value1');
await box.delete('key1');
Clear
var box = await Hive.openBox('dataBox');
await box.clear();
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});
}
- 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
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';
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});
}
- 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());
}
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');
}
}
}
- 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),
),
);
}
}
- 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)