Hive Databases as a NoSQL Database for Flutter

Hive Databases

Apache Hive is an open source data warehousing and SQL-like query language for big data processing on Apache Hadoop. It provides a structure to store, manage, and query large datasets, enabling users to perform batch processing and analytics on the data stored in the Hadoop Distributed File System (HDFS). Hive supports SQL-like query language called HiveQL, which allows for simple data summarization, ad-hoc queries, and analysis of large datasets.

Key Components of hive Database for Flutter

Hive Box

  • A Hive Box is a key-value store that is used to store data in Hive.
  • The key is a string and the value can be of any type that implements Hive's Type Adapter.

Hive Adapter

  • Hive Adapter is a class that implements the Type Adapter interface and is used to define how data is serialized and deserialized when stored in a Hive Box.

Hive Field

  • Hive Field is a Dart class that is used to annotate properties of a Dart class that should be stored in Hive.
  • The annotations specify the type of the field and any other metadata that is required for serialization and deserialization.

Hive List

  • Hive List is a class that represents a list of Hive objects. The Hive List class provides a convenient way to store and retrieve lists of objects in Hive.

Hive Map

  • Hive Map is a class that represents a map of Hive objects. The Hive Map class provides a convenient way to store and retrieve maps of objects in Hive.

Hive Databases as a NoSQL Database for Flutter

01. Easy to use

Hive has a simple and intuitive API that makes it easy for developers to implement in their Flutter applications.

02. Fast performance

Hive is designed to be fast and efficient, providing fast access to stored data and real-time manipulation of data.

03. Lightweight

Hive is a lightweight solution that does not require a lot of resources, making it suitable for use in resource-constrained environments.

04. Secure

Hive provides robust security features that help protect stored data from unauthorized access and tampering.

05. Cross-platform compatibility

Hive is written in Dart, the language used by Flutter, and is designed to be compatible with both iOS and Android platforms.

06. Flexible data storage

Hive supports a variety of data types, including integers, strings, lists, and maps, allowing developers to store a wide range of data in a flexible and efficient manner.

Benefits

Speed and Efficiency

Hive, as a fast key-value database optimized for mobile devices, makes it a suitable choice for offline storage. Its efficient binary format of data storage makes it faster compared to SQLite databases.

User-Friendly

Hive has a straightforward and easy-to-use API, which makes storing and retrieving data a breeze, even for those who are new to database programming.

Expandable

Hive allows an unlimited number of databases and tables, making it capable of fulfilling the storage requirements of any size of applications.

 

Cross-Platform

Hive can be used on both Android and iOS, making it an excellent choice for cross-platform app developmen

Safe Type Management

Hive ensures data is stored and retrieved in the correct format by providing type safety for stored data, reducing the chances of errors and bugs.

Data Upgrading

Hive supports data migration, allowing for a seamless upgrade of the database to a newer version without any loss of data.

 

Secure

Hive provides data encryption, ensuring sensitive information can be stored securely.

 

 

Related Insights

Let’s Start our Implementation:

Before moving on to the CRUD operations of the database, First, we get data from API response and Stored in Hive boxes with State management of Redux.

We have already published an article on how to get data from API response and stored data in Redux. here is the link👉 Redux-State management with Redux in Flutter. Using this Knowledge you can build your code with Redux. Now we can Skip this Step and directly move to how to store data In the HIVE database from Redux.

When users open App as offline display data from the database. when the user has a network connection get data from the server, Update DB and display data (user request → server → get response → Redux (Reducer) → Update DB(Hive) → Display data ).

Add Dependencies:

Add the hive, hive_flutter, and path_provider packages to your pubspec.yaml file. we also need to add hive_generator and build_runner to the dev dependencies.

dependencies:
hive: ^2.0.4
hive_flutter: ^1.1.0
path_provider: ^2.0.8
flutter_redux: ^0.8.2
redux: ^5.0.0
redux_thunk: ^0.4.0dev_dependencies:
hive_generator: ^1.1.1
build_runner: ^2.1.7

First, we initialize Hive in Main Function before we perform any operations related hive database.

await Hive.initFlutter();
Initialize hive with the path of the directory .it’s Optional. We can find the location on HDFS(Hadoop Distributed File System) where the directories for the database are made by checking hive.

Directory directory = await getApplicationDocumentsDirectory();
Hive.init(directory.path);
Hive supports all primitive types, List, Map, DateTime and Uint8List. If you want to store other objects, you have to register a TypeAdapter which converts the object from and to binary form. When you want Hive to use a TypeAdapter, you have to register it.

Hive.registerAdapter(ServiceAdapter());
main.dart

void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Directory directory = await getApplicationDocumentsDirectory();
Hive.init(directory.path);
Hive.registerAdapter(ServiceAdapter());
runApp(MyApp());
}

final navigatorKey = GlobalKey();

class MyApp extends StatefulWidget{
const MyApp({Key? key}) : super(key: key);
_MyAppState createState()=>_MyAppState();
}

class _MyAppState extends State {
final store = Store(
appReducer,
initialState: AppState.initial(),
middleware: [thunkMiddleware, apiMiddleware, ],
);

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

@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);

return StoreProvider(
store: this.store,
child: MaterialApp(
builder: (context, child) {
return MediaQuery(data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child:child!);
},
navigatorKey: navigatorKey,
initialRoute: ‘/feed’,
onGenerateRoute: RouteGenerator.generateRoute,
debugShowCheckedModeBanner: false,
)
);
}
}
Get List of data from Hive

hivemodel.dart:

Create a model class for the hive. Two things are needed for that: An instance of the adapter and a typeId. Every type has a unique typeId which is used to find the correct adapter when a value is brought back from the disk. All typeIds between 0 and 223 are allowed. Make sure to use typeIds consistently. Your changes have to be compatible with previous versions of the box. It’s recommended to register all TypeAdapters before opening any boxes.

import ‘package:hive/hive.dart’;
part ‘hivemodel.g.dart’;

@HiveType(typeId: 1,adapterName: “ServiceAdapter”)
class GetService{
@HiveField(0)
String name;

@HiveField(1)
String Lastname;

@HiveField(2)
String status;

GetService({required this.name,required this.status,required this.lastname});
}
hivemodel.g.dart

The hive_generator package can automatically generate TypeAdapters for almost any class.

To generate a TypeAdapter for a class, annotate it with @HiveType and provide a typeId (between 0 and 223)
Annotate all fields which should be stored with @HiveField
You can Specify part ‘hivemodel.g.dart’ in hivemodel.dart .
Open terminal and Run flutter packages pub run build_runner build then automatically create hivemodel.g.dart .
// GENERATED CODE – DO NOT MODIFY BY HAND

part of ‘hivemodel.dart’;

// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************

class ServiceAdapter extends TypeAdapter {
@override
final int typeId = 1;

@override
GetService read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return GetService( name: fields[0] as String, status: fields[2] as String, lastname: fields[1] as String, ); } @override void write(BinaryWriter writer, GetService obj) { writer ..writeByte(3) ..writeByte(0) ..write(obj.name) ..writeByte(1) ..write(obj.lastname) ..writeByte(2) ..write(obj.status); } @override int get hashCode => typeId.hashCode;

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ServiceAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

feedscreen.dart:

await Hive.openBox(‘service’);

when we start to store data in the hive. we need to open Hive Box. here ‘service’ is the name of the box. It is case-insensitive.

class _FeedScreenState extends State {
int listLenght = 0;

@override
void initState(){
hiveopen();
}

hiveopen() async {
box = await Hive.openBox(‘service’);

setState(() {
ListServiceItems = box.values.toList();
});
}

putalldata(RequestProps props) async {
box = await Hive.openBox(‘service’); //open box
box.clear(); //clear all values in Hive
for(int i=0; i<listLenght; i++) {
GetService adddata = new GetService(
name: props.feedsuccess!.success![i].waiterId!.firstName.toString(),
status: props.feedsuccess!.success![i].status.toString(),
lastname: props.feedsuccess!.success![i].waiterId!.lastName.toString());
box.add(adddata); // add data from hive
}
setState(() {
ListServiceItems = box.values.toList(); //get values from Hive
});
}

var data = {
“userId”:userid.toString()
};

void handleInitialBuild(RequestProps props) {
props.feedsuccessapi(“”);
}

@override
Widget build(BuildContext context) {
return StoreConnector<AppState, RequestProps>(
converter: (store) => mapStateToProps(store),
onInitialBuild: (props) => this.handleInitialBuild(props),
builder: (context, props) {
Widget ? body;

if (props.loading == true) {
body = Center(
child: CircularProgressIndicator(),
);
}

else if(props.feedsuccess != null) {
listLenght = props.feedsuccess!.success!.length;
Timer(Duration(milliseconds: 100), () {
putalldata(props);
});
}

else if(props.error != null){
print(“error”);
}

return Scaffold(
appBar: AppBar(
title: Text(‘Home page’),
),

body:
ListView.builder(
itemCount: ListServiceItems.length,
itemBuilder: (context, position) {
GetService getdeatils = ListServiceItems[position];
var name = getdeatils.name;
var status = getdeatils.status;
var lastname = getdeatils.lastname;
return Card(
child: Container(
padding: EdgeInsets.all(7),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text( “USER NAME : “+name + ” “+ lastname, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),),
SizedBox(height: 10,),
Text(“STATUS MESSAGE : “+ status),
],
)
)
);
})

);
});
}
}
Crud Operations:
Create Read Update Delete

Create Read Update Delete

Add the Icon button in feedscreen.dart . When the user click Add button and edit button open the AddandUpdate screen and pass the required parameter values.

IconButton(
icon: Icon(Icons.add),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (_) => UpdateData( getServicemodel: null, position: -1, isEdit:false,)));
},
)IconButton(
icon: Icon(Icons.edit,color: Colors.blue,),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => UpdateData(
isEdit: true,position: position, getServicemodel:getdeatils,)));
}),

ADD/Update Screen:

Here, we open the box and then use the add() method to append the data to our box. you can also use the put() method, the difference is with put() you have to specify the key for each value – box.put(‘key’, item), but add() just gives each value an index and auto increments it.

Read data from Hive:

box.get(‘key) – get the value from a key.
box.getAt(index) – get the value from an index created with box.add().
box.values – this returns an iterable containing all the items in the box.
Updatedate.dart:

class UpdateData extends StatefulWidget {
bool isEdit;
int position = -1;
GetService? getServicemodel = null;
UpdateData( {Key? key, required this.isEdit,required this.position, required this.getServicemodel}) : super(key: key);

@override
_UpdateDataState createState() => _UpdateDataState();
}

class _UpdateDataState extends State {
var firstNameController = TextEditingController();
var lastNameController = TextEditingController();
var statusController = TextEditingController();

@override
Widget build(BuildContext context) {
if (widget.isEdit) {
firstNameController.text = widget.getServicemodel!.name;
lastNameController.text = widget.getServicemodel!.lastname;
statusController.text = widget.getServicemodel!.status;
}

return Scaffold(
appBar: AppBar(
title: Text(‘ADD and Update’)),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
SizedBox(height: 30),
Row(
children: [
Text(“FIRSTNAME :”, style: TextStyle(fontSize: 18, color: Colors.black)),
SizedBox(width: 20),
Expanded(
child:
TextField(controller: firstNameController,
textInputAction: TextInputAction.next,
)),
],
),
Row(
children: [
Text(“LASTNAME :”, style: TextStyle(fontSize: 18,color: Colors.black)),
SizedBox(width: 20),
Expanded(
child:
TextField(controller: lastNameController,
textInputAction: TextInputAction.next,
)),
],
),
Row(
children: [
Text(“STATUS :”,style: TextStyle(fontSize: 18,color: Colors.black)),
SizedBox(width: 40),
Expanded(
child:
TextField(controller: statusController,
textInputAction: TextInputAction.next,
)),
],
),
SizedBox(height: 20,),
MaterialButton(
color: Colors.blue,
child: Text(“SAVE”,
style: TextStyle(color: Colors.white, fontSize: 18, )),
onPressed: () async {
var firstName = firstNameController.text;
var lastName = lastNameController.text;
var status = statusController.text;
if (firstName.isNotEmpty &
lastName.isNotEmpty &
status.isNotEmpty) {
GetService updatedata = new GetService(
name: firstName,
lastname: lastName,
status: status);

if (widget.isEdit) {
var box = await Hive.openBox(‘service’);
box.putAt(widget.position, updatedata);
} else {
var box = await Hive.openBox(‘service’);
box.add(updatedata);
}
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (_) => FeedScreen()),
(r) => false);
}
},
)
],
),
),
),
);
}
}

Delete:

box.delete(‘key) – get the value from a key.
box.deleteAt(index) – get the value from an index created with box.add().
box.deleteAll(keys) – accepts an iterable of keys, and deletes all the keys given.
IconButton(
icon: Icon(Icons.delete,color: Colors.red,),
onPressed: (){
final box = Hive.box(‘service’);
box.deleteAt(position);
setState(() => {
ListServiceItems.removeAt(position)
});
})
Demo video for online and offline mode:

 

 

 

Connect With Us!