Last updated:
0 purchases
hive cache manager
A wrapper package that lets you write minimum amount of cache related code
Features #
π€©οΈ Simple & fast coding
β€οΈ Uses hive for caching
π Uses flutter_secure_storage to store encryption key
πΈ Uses ValueListenableBuilder to listen data changes
π₯³ Makes it easy to store custom models
By using this package, you do not need to write separate Hive related code for each of your models. This package provides a generic cache manager class that handles hive box operations.
Getting started #
Add this package to your pubspec.yaml file and run pub get
dependencies:
hive_cache_manager: latest
copied to clipboard
Usage #
import 'package:hive_cache_manager/hive_cache_manager.dart';
copied to clipboard
1) Create your custom model #
Let's say that we want to store information about books. We can name the dart file book.dart
class Book {
String isbn;
String title;
String author;
int year;
//constructor
Book({required this.title, required this.author,
required this.year, required this.isbn});
}
copied to clipboard
2) Use hive annotations and define the name of your type adapter file #
These steps are necessary for using the hive package.
Use @HiveType and @HiveField annotations.
Put part 'model_file_name.g.dart' on the top of your model file.
(model_file_name must match exactly to your model file's name)
part 'book.g.dart';
@HiveType(typeId: 1)
class Book {
@HiveField(0)
String isbn;
@HiveField(1)
String title;
@HiveField(2)
String author;
@HiveField(3)
int year;
//constructor
Book({required this.title, required this.author,
required this.year, required this.isbn});
}
copied to clipboard
3) Generate the type adapter file #
Add the build_runner package under your dev_dependencies in pubspec.yaml:
dev_dependencies:
#code generation
build_runner: latest
copied to clipboard
And then run the command below in your terminal to generate the type adapter for the Book class.
This step is also necessary for using the hive package.
flutter packages pub run build_runner build
copied to clipboard
This will create the model_file_name.g.dart next to your model file.
π No need to add "hive_generator" package in your pubspec.yaml. This package is already included in the hive_cache_manager. Just run the command above.
4) Extend your model from IHiveModel #
IHiveModel is a special abstract class in the hive_cache_manager.
When extended from this class, your model must override the "mapKey" computed property.
If you want to store your objects with model specific keys, you can use this property to set which key will be used when saving the model object in the hive box.
For example, we may select ISBN number as key for the key-value pairs in the hive box.
The International Standard Book Number (ISBN) is a numeric commercial book identifier that is intended to be unique.
import 'package:hive_cache_manager/hive_cache_manager.dart';
@HiveType(typeId: 1)
class Book extends IHiveModel{
@HiveField(0)
String isbn;
@HiveField(1)
String title;
@HiveField(2)
String author;
@HiveField(3)
int year;
//constructor
Book({required this.title, required this.author,
required this.year, required this.isbn});
//define your unique key here
@override
String get mapKey => isbn;
}
copied to clipboard
Alternatively, you can use combination of your properties or any string you like.
@override
String get mapKey => "$isbn - $title";
copied to clipboard
If you want to store your objects with auto incremented keys, you may just return an empty string (or any string). In this case, this property will not be used. So, it doesn't matter what you return in the mapKey.
@override
String get mapKey => "";
copied to clipboard
5) Create a cache manager class for your model #
ICacheManager<T extends IHiveModel> is a special abstract class in the hive_cache_manager.
In order to handle hive box operations create one manager class for your model.
Since we extended our Book class from IHiveModel, we can use it instead of T.
When extended from ICacheManager, registerAdapters method must be overridden.
Register an object from your generated type adapter class in this method.
import 'package:hive_cache_manager/hive_cache_manager.dart';
import '../model/book.dart';
import 'package:hive/hive.dart';
class BookCacheManager extends ICacheManager<Book>{
BookCacheManager(super.boxName);
@override
void registerAdapters() {
if(!Hive.isAdapterRegistered(1)){ //1 is the type id of the Book class
Hive.registerAdapter(BookAdapter()); // If not registered, register the generated BookAdapter here.
}
}
}
copied to clipboard
π Now, BookCacheManager class can handle all the box operations such as putting or deleting a Book object.
π BookCacheManager also provides a ValueListenableBuilder that is connected to the hive box which you put your Book objects into. This way you can listen to the changes on the box without using setState((){}).
6) Initialize Hive before using #
This step is also necessary for using the hive package.
You can initialize it in main before the runApp .
import 'package:hive_flutter/hive_flutter.dart';
void main() async{
await Hive.initFlutter("hive_db");
runApp(const MyApp());
}
copied to clipboard
7) Create a manager object and explicitly call its init method #
init method runs the registerAdapters() method of the BookCacheManager and then opens a hive box that can store Book objects.
If the isEncrypted parameter is true, it creates an encrypted box without making you write any encryption or flutter_secure_storage related code.
Use isEncrypted: false if you don't want to encrypt your data.
BookCacheManager bookCacheManager = BookCacheManager("books_hive_box");
// put true if you want an encrypted box
await bookCacheManager.init(isEncrypted: true);
copied to clipboard
8) Create some model objects #
Book firstBook = Book(
title: 'Lord of The Rings - The Fellowship of the Ring',
author: 'J. R. R. Tolkien',
year: 1954,
isbn: '9780618260515',
);
Book secondBook = Book(
title: 'Lord of The Rings - The Two Towers',
author: 'J. R. R. Tolkien',
year: 1954,
isbn: '9780261102361',
);
Book thirdBook = Book(
title: 'Lord of The Rings - The Return of the King',
author: 'J. R. R. Tolkien',
year: 1955,
isbn: '9780007136575',
);
copied to clipboard
ππΌββοΈAny other Lord of The Rings fan here??
9) Do any operation you want on the hive box via the Cache Manager #
addItem and addItems methods add value(s) with autoincremented keys.
putItem and putItems methods add value(s) with model specific keys (uses the mapKey property).
Put Examples:
await bookCacheManager.putItem(item: firstBook);
await bookCacheManager.putItems(items: [firstBook, secondBook, thirdBook]);
//access an item with its mapKey property
await bookCacheManager.removeItem(key: secondBook.mapKey);
await bookCacheManager.removeItems(keys: [firstBook.mapKey, thirdBook.mapKey]);
await bookCacheManager.clearAll();
await bookCacheManager.closeBox();
print(bookCacheManager.getItem(key: thirdBook.mapKey)?.year);
print(bookCacheManager.getValues().length);
print(bookCacheManager.hiveBoxLength);
print(bookCacheManager.isHiveBoxOpen);
print(bookCacheManager.isHiveBoxEmpty);
print(bookCacheManager.isHiveBoxNotEmpty);
copied to clipboard
Add Examples:
List<Book> books = [firstBook, secondBook, thirdBook];
await bookCacheManager.addItems(items: books);
print("${bookCacheManager.getValues().first.isbn} is equal to 9780618260515");
// remove the object named "thirdBook" from the hive box
// since the objects were added with autoincremented keys, the key of the "thirdBook" should be 2
// (the first item's key is 0)
await bookCacheManager.removeItem(key: 2);
// read the values whose keys start at 0 and ends at 1 (inclusive)
Iterable<Book> otherBooks = bookCacheManager.getValuesBetween(startKey: 0, endKey: 1);
// put the remaining model objects in an Iterable
Iterable<Book> remainingBooks = [firstBook, secondBook];
// "otherBooks" and "remainingBooks" should be equal
// override the toString() method in Book class in order to print pretty iterables.
print("$otherBooks is equal to $remainingBooks");
copied to clipboard
For more detailed code samples check the Github repo of this project (related links are below):
hive_autoincrement_keys_test.dart
hive_model_specific_keys_test.dart
Example project
10) Show the data on the UI #
Here is a screen recording of the Example project.
The + button on the App Bar adds 3 Book objects to the hive box.
With the help of ValueListenableBuilder, we can listen to the changes on the box.
On the body of the Scaffold, the data in the box is shown using 3 different ways.
The first list shows all the data in the hive box
The second list was filtered by the keys (Books that have "9780618260515", "9780007136575" keys were shown)
The third list was filtered by a property of the Model Class (only the books that have "1955" in their year information were shown)
βοΈ Deleting an item from one list is instantly recognized and the change is reflected in all lists.
How to Use ValueListenableBuilder #
Access the ValueListenableBuilder by the "getValueListenableBuilder" method of the cache manager.
bookCacheManager.getValueListenableBuilder(
buildLayout: buildBooksLayout,
keys: filterKeys,
)
copied to clipboard
This method requires 2 parameters. The first one (buildLayout) is a Function that uses the data that is being listened to. Here is the type of the buildLayout parameter:
Widget Function(List<T> data) buildLayout
copied to clipboard
In the example project, it was implemented as below:
Widget buildBooksLayout(List<Book> books) {
// consume the data here
// show the data on UI and define your business logic
return books.isEmpty
? const Center(child: Text("There is no data to show"))
: buildListView(books);
}
Widget buildListView(List<Book> books){
return ListView.builder(
itemCount: books.length,
itemBuilder: (context, index) {
final item = books.elementAt(index);
return _BookCard(book: item);
},
);
}
copied to clipboard
(_BookCard is a Stateless widget that defines the UI layout of a Book object. It uses Card and ListTile widgets. You can create any design/layout you like. Check the _BookCard widget on Github to see the codes.)
The second parameter controls the filtering by key. It's an optional parameter. If given, the data in the hive box is filtered by the given keys. And only the filtered data is passed to the buildLayout function.
Show all the data in the hive box: #
Don't provide any keys to show all the data in the hive box.
Container(
child: bookCacheManager.getValueListenableBuilder(
buildLayout: buildBooksLayout,
),
)
copied to clipboard
Filter only specific books and show them: #
Provide the keys parameter to filter by keys.
It automatically filters the Books by their keys and only listens to the changes related to the filtered objects.
Container(
child: bookCacheManager.getValueListenableBuilder(
buildLayout: buildBooksLayout,
keys: ["9780618260515", "9780007136575"], //ISBN of The Fellowship of the Ring & The Return of the King
),
)
copied to clipboard
Alternatively, create your own filters in your custom ValueListenableBuilder widget: #
Use the cache manager's getListenable method to get the ValueListenable. Filter or order your data in the builder method.
Container(
child: ValueListenableBuilder(
valueListenable: bookCacheManager.getListenable(),
builder: (context, box, widget) {
List<Book> data = [];
for (Book book in bookCacheManager.getValues()) {
//filter the books whose year information is 1995
//change this filter as needed
if (book.year == 1955) {
data.add(book);
}
}
// you can order your data here as well
return buildLayout(data);
},
),
)
copied to clipboard
Additional information #
This package depends on the flutter_secure_storage package in order the store the encryption key. Be sure to make all the necessary configurations for all platforms (eg. Web and Linux).
Also, flutter_secure_storage currently obliges the minSdkVersion to be >=18.
You can also get a compileSdkVersion incompatibility while using flutter_secure_storage (it obliges minSdkVersion >= 33)
Change these properties in your gradle file (/android/app/build.gradle) accordingly. For Flutter 2.8 or later, do the steps below:
add these lines in your local.properties file(/android/local.properties):
flutter.compileSdkVersion=33
flutter.minSdkVersion=18
copied to clipboard
reference to the newly added version numbers in your gradle file:
compileSdkVersion localProperties.getProperty('flutter.compileSdkVersion').toInteger()
minSdkVersion localProperties.getProperty('flutter.minSdkVersion').toInteger()
copied to clipboard
If you find any improvements, consider contributing to this project. Contributions are welcome & appreciated! Github link: hive_cache_manager.
Lastly, please give a like & star if you find this package helpful π«
Licence #
The MIT License (MIT)
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.