Handling Local Data Persistence in Flutter with Hive
Storing and persisting data locally between app launches is crucial in mobile app development. While options like shared_preferences and SQFLite are viable for small key-value pairs and complex relational data, respectively, Hive Flutter stands out as a superior choice. It's a lightweight, NoSQL, key-value database ideal for both mobile and web applications in Flutter and Dart. Offering ease of use, cross-platform support, and exceptional performance without native dependencies, Hive Flutter simplifies data handling, ensuring security and efficiency.
Prerequisites
- Basic Knowledge of databases, How data is stored and deleted.
- Hive package:
You need to install the Hive package in your Flutter project. Hive is a lightweight and fast NoSQL database that allows you to store data in key-value pairs.
Setting Up Hive
You must first include the Hive package as a dependency in your pubspec.yaml file to configure Hive in a Flutter project. Then, in your main.dart file, call the Hive.init() method to initialize Hive. By using the Hive.openBox() function after startup, you can create a Hive box to store data. Using key-value pairs, you can then save and retrieve data from the box. Additionally, registering Hive adapters to match your data models to the boxes is advised. Making an adapter class that extends HiveTypeAdapter and registering it with Hive using the Hive.registerAdapter() method will enable you to accomplish this. You can quickly set up Hive in your Flutter project and begin using it to store and retrieve data by following these steps.
Create a New Flutter Project in your IDE, or use the following command:
Open the Project in an IDE, the most commonly used are android studio or VS Code. For VS Code just run this command:
Or go to the directory where the Project is created and run this command to open the project in VS Code:
After Creating the Project we need to add Hive and Hive Flutter packages to our pubsec. yaml file. Go to pubsec. yaml file and add the following dependencies:
[versions] should be replaced with the latest versions of the given dependencies for example:
Dependencies are added in Flutter to include external libraries or packages that provide additional functionality to your Flutter application. These libraries can help you save time and effort by providing pre-built solutions for common problems or features, such as working with APIs, handling image loading and caching, or implementing animations.
Understanding Boxes in Hive
Hive Flutter works similarly to a map in C++. Hive Flutter organizes all of its data into boxes. In SQL, a box is comparable to a table, however, unlike a table, a box can hold anything.
A single box might be sufficient for a small app. Boxes are a wonderful tool for organizing your data while solving more complex tasks. Sensitive data can also be stored in encrypted boxes.
Open Box
A box must be opened to be used. This transfers all of the data from the local storage into memory for normal boxes so that it may be accessed right away.
Here is a Description of the parameters:
Parameter | Description |
---|---|
name | The name of the box specifies the storage location and is used to check if a box already exists. It is case-insensitive. When choosing a name for your box, it's a good practice to use a descriptive and unique name that reflects the type of data you will be storing in the box. |
encryptionKey | The key has to be a byte array with a length 32 and is used to encrypt and decrypt all values in the box. It's important to note that the encryptionKey should be kept secret and not shared with anyone. If you lose the encryptionKey, you won't be able to decrypt the data stored in the box. |
keyComparator | By default, keys are sorted lexicographically. This parameter allows you to provide a custom sorting order. By default, Hive sorts the keys in lexicographical order, which means that the keys are sorted based on their Unicode values. |
compactionStrategy | Specify your own rules for automatic compaction. By default, the compactionStrategy parameter is set to HiveCompactionStrategy.everyNthWrite with a compactionFrequency of 20. |
crashRecovery | If your app is killed while a write operation is running, the last entry might be corrupted. This entry is deleted automatically when the app starts again. If you don't want this behavior, you can disable it. |
path | By default, boxes are stored in the directory given to Hive.init(). With this parameter, you can specify the location where the box should be stored. If you want to specify a custom directory path for your box, you can pass the directory path as the path parameter. |
bytes | Instead of using a file as a backend, you can provide the box in binary form and open an in-memory box. It's important to note that once you set the byte parameter for a box, you cannot change it without losing all of the data stored in the box. |
E | The optional type parameter specifies the type of the values in the box. Supported data types include all primitive types, some collection types (such as List and Map), and custom data models that are registered with Hive using adapters. |
All provided parameters are ignored if the box is already open and is instantly returned.
You can read, write, and delete entries once you have a box instance.
Get Open Box
Hive stores a reference to all open boxes. If you want to get an already opened box, you can use:
Because you don't have to pass the box between widgets, this solution is extremely helpful for Flutter apps.
Close Box
Close a box if you won't be using it again. After all current read and write operations have been completed, all cached keys and values for the box are removed from memory and the box file is closed.
It is acceptable to leave a box open while the app is running. Simply leave it open in case you ever need a box again.
Before your application exits, you should call Hive.close() to close all open boxes. Don't worry if the app is killed before you close Hive, it doesn't matter.
Type Parameter: Box < E >
You can declare that a box can only hold values of a particular type when you open it. An example of how a user box might be opened is as follows:
Subtypes of Users may also be included Here.
You must give Hive.box() the same type parameter. The same box cannot be opened more than once with different types of arguments.
📝 Note:
Due to Dart restrictions, generic type arguments like BoxList> are not supported.
Using a Lazy Box in Hive
When a box is opened in Hive Flutter, its full contents are automatically saved in memory. Small and medium-sized boxes benefit greatly from this behavior because you may retrieve their contents without using async calls.
It could be advantageous to load values slowly for larger boxes or programs that use a lot of memory. All of a lazy box's keys are read and saved in memory when it is opened. When a value is accessed, Hive locates it precisely on the disc and retrieves the value.
To get an already opened lazy box call:
Storing Sensitive Information with Encrypted Boxes
Data must occasionally be stored safely on the disc. AES-256 encryption is supported by Hive out of the box.
A 256-bit (32-byte) encryption key is all you need. Hive offers a helper function that uses the Fortuna random number generator to provide a safe encryption key.
Simply hand the key over after opening a box:
📝 Note:
- The flutter_secure_storage package was used in the example above to store the encryption key, but you can use any package or method you like to safely store the encryption key after your application has been closed.
- Only values are encrypted while keys are stored in plaintext.
- There is no check if the encryption key is correct. If it isn't, there may be unexpected behavior.
Initializing Hive
It's preferable to initialize Hive inside the main() function of your Flutter app to prevent any errors since it needs to be initialized before we load any boxes. Remember to use Hive.init() to initialize Hive if you're using it in a pure Dart application that isn't based on Flutter.
In Hive Flutter, The majority of primitive types, including List, Map, DateTime, and Uint8List, are supported by Hive. However, there are situations when you may need to store unique model classes that facilitate data administration.
Use a TypeAdapter, which creates the to and from binary methods, to accomplish this.
TypeAdapters can be produced automatically or manually written. It is usually preferable to utilize code generation to create the necessary methods because it helps to avoid any errors that could happen while writing by hand (and also because it is quicker).
A TypeAdapter must be registered for Hive to use it. An instance of the adapter and a typeId are required for that. When a value is brought back from the disk, the typeId of each type is utilized to identify the proper adapter. All types in the range of 0 to 223 are acceptable.
To construct the TypeAdapter for Hive, you must add several dependencies. The following should be added to your pubspec.yaml file:
📝 Note:
- Use typeIds consistently at all times. Your modifications must work with earlier iterations of the box.
- It is advised to register every TypeAdapter before unpacking any packages.
- Ensure that you use unique names for each box you create in your application, as Hive does not allow duplicate box names.
- When storing and retrieving data, it is essential to make sure that the data types match. Hive offers type safety by allowing developers to specify data types for each box.
Annotate the model class to use code generation:
Storing and Retrieving Data with Hive
Use the Hive box reference and the put() method if you need to save data. A key-value pair is accepted by this method.
The Name and the Company are saved as two key-value pairs in this location.
You can utilize auto-incrementing keys because Hive also supports integer keys. This can be helpful if you want to get values by their indices and are storing several values (sort of like a list). You could stock in this way:
Use the get() function on the box object to read data. All that is required to retrieve its value is the key.
Using the index, you can read using auto-incrementing values as follows:
It follows 0-Indexing.
📝 Note:
- To maintain the integrity of the data, a box must be opened before accessing it and closed after use.
- You must specify distinct keys for each value that Hive stores in key-value pairs.
Updating and Deleting Data with Hive
You can use the same put() function that you used to store the value to update the data for a specific key. This will substitute the newly supplied value for the value already existing at that key.
The putAt() method can update the value at a certain index if you are using auto-incrementing values.
0-based Indexing is followed throughout
You can use the delete() method and the key to erase data.
This will remove the values that were present for those specific keys. Now, if you attempt to use these keys to call the get() method, it will return null data.
In Hive Flutter, The deleteAt() method can be used with auto-incrementing variables by passing the index.
📝 Note:
- You should make sure that modified data is of the same data type as the original record when changing data. It's critical to update data with the appropriate data type since Hive offers type safety.
- Updates and deletions are carried out as atomic operations with the help of Hive's transactions. To maintain data integrity, you should use transactions when deleting or changing data.
Hive is a "data warehouse infrastructure" built on top of Hadoop that allows you to query and analyze data stored in a Hadoop Distributed File System (HDFS) using a SQL-like language called HiveQL or HQL.
To query data with Hive, you need to follow these basic steps:
Create a Hive database:
Use the CREATE DATABASE command to create a new database in Hive where you can store your data.
For example:
Create a Hive table:
Use the CREATE TABLE command to define the structure of your data in Hive. You need to specify the columns, their data types, and any constraints or partitioning options.
For example:
This command creates a table called mytable with three columns: id, name, and age. The data is stored in delimited format with commas separating the fields.
Load data into the Hive table:
Use the LOAD DATA INPATH command to load data into the Hive table. You need to specify the path to the input data file or directory.
For example:
This command retrieves the names and ages of all records in the mytable table where the age is greater than 18.
Analyze the Hive table:
Use the ANALYZE TABLE command to gather statistics about the Hive table. This information can help Hive optimize queries and improve performance.
For example:
This command computes statistics for the mytable table. These are the basic steps to querying data with Hive. Hive also provides many advanced features, such as support for user-defined functions (UDFs), window functions, and subqueries.
Migrating Data with Hive
Migrating data with Hive involves transferring data from one storage system to another. The source and target storage systems can be different Hadoop file systems, or they can be different types of databases, such as MySQL or Oracle. Here are the steps to migrate data with Hive:
Create a New Hive Database
Create a new Hive database on the target system to which you want to migrate your data.
For example:
Create a New Hive Table
Create a new Hive table on the target system that has the same schema as the source table. You can use the CREATE TABLE statement with the same column names, data types, and partitioning options.
For example:
This command creates a new table called mynewtable on the target system with the same schema as the source table. The table is partitioned by year and month and stored in ORC format.
Load Data into the New Table
Load data from the source table into the new table on the target system. You can use the INSERT INTO statement with the SELECT statement to load data.
For example:
This command inserts data from the source table myoldtable into the new table mynewtable on the target system. It inserts only the data for the partition with year=2022 and month=1.
Verify the Data
Verify that the data has been migrated correctly by running queries on the new table.
For example:
This command retrieves the names and ages of all records in the mynewtable table for the partition with year=2022 and month=1.
These are the basic steps to migrate data with Hive. Hive provides many advanced features, such as dynamic partitioning, bucketing, and serialization formats, that can help optimize data migration performance.
Best Practices and Tips
Optimize Performance in Hive
Here are some tips to optimize performance in Hive Flutter:
-
Use Partitioning:
Partitioning your data in Hive can significantly improve query performance. It allows Hive to prune partitions that do not match query criteria, reducing the amount of data that needs to be scanned. You can partition your data by date, time, or any other relevant column.
-
Use bucketing:
Bucketing is a technique in Hive that allows you to group data based on a specific column. This can improve performance by reducing the amount of data that needs to be scanned. Bucketing works best when the data is evenly distributed across buckets.
-
Use appropriate file formats:
Hive supports various file formats for storing data, but some formats are more efficient than others. For example, the ORC and Parquet formats are optimized for performance and storage space. They provide column-level compression, which reduces the amount of data that needs to be read from the disk.
-
Optimize query performance:
You can optimize query performance in Hive by using appropriate join types, reducing the number of MapReduce jobs, and using appropriate indexing.
Handling Errors in Hive
In Hive, handling errors efficiently is critical to ensure data integrity and prevent data loss. Here are some techniques you can use to handle errors in Hive:
-
Use ACID transactions:
Hive supports ACID transactions, which ensures that data is consistent and durable. ACID transactions provide the ability to rollback a transaction if an error occurs, preventing data loss. -
Monitor logs:
Hive logs provide detailed information about errors and exceptions that occur during runtime. You can use this information to diagnose and fix errors. -
Use error handling functions:
Hive provides several error handling functions that you can use to handle errors. For example, the IFNULL function returns a default value if a column is null. The COALESCE function returns the first non-null value from a list of columns.
Conclusion
-
Hive is a lightweight and fast NoSQL database solution for Flutter and other platforms. To use Hive in Flutter, you need to add the hive and hive_flutter packages to your pubspec.yaml file.
-
You can define a Hive box by creating a class that extends HiveObject and annotating it with @HiveType() and @HiveField() annotations.
-
By using the Hive.openBox() method and the box's name as an argument, you can open a Hive box. You can add data to a Hive box by calling the box.add() method and passing in an instance of your Hive class. You can retrieve data from a Hive box by calling the box.get() method and passing in the key of the item you want to retrieve. By calling the box, you can update data in a Hive box. using the put() method while providing both the modified data and the item's key.
-
You can delete data from a Hive box by calling the box.delete() method and passing in the key of the item you want to delete. Hive supports queries using the box.values.where() method and the HiveQuery class. Hive also supports adapters for serializing and deserializing complex objects, and encryption for securing sensitive data.
-
Hive enables you to store and retrieve data in your Flutter app quickly and easily without the need for a challenging SQL database configuration. Hive is a fantastic option for both novice and seasoned Flutter developers because it offers a quick and easy way to manage data in your app.