π Caching, storing local data
We use Hive database to store data locally. Hive is a lightweight, powerful database which runs fast on the device.
Unless you absolutely need to model your data with many relationships, choosing this pure-Dart package with no native dependencies can be the best option.
Hive is centered around the idea of boxes
. Box
has to be opened before use. In addition to the plain-flavored Boxes,
there are also options which support lazy-loading of values and encryption.
Initializationβ
Hive needs to be βinitializedβ to, among other things, know in which directory it stores the data. A service for hive was created.
The setupHive
method initializes hive for flutter and registers adapters and is called in main
.
IHiveRepository<E>
is an mixin that manages Hive box opening, where E
is a specific type depending on the type of data being stored.
Hive service
Future<void> setupHive() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
_registerAdapters();
}
void _registerAdapters() {
Hive.registerAdapter<User>(UserAdapter());
}
abstract class IHiveRepository<E> {
Box<E>? _box;
String get boxKey;
Future<Box<E>> get box async {
_box ??= await Hive.openBox<E>(boxKey);
return _box!;
}
}
Boxesβ
Data can be stored and read only from an opened Box
. Opening a Box
loads all of its data from the local storage into memory for immediate access.
- Open box
Hive.openBox('userBox');
- Get an already opened instance
Hive.box('name');
There are two basic options of adding data - either call put(key, value)
and specify the key yourself,
or call add
and utilize Hive's auto-incrementing keys. Unless you absolutely need to define the keys manually,
calling add is the better and simpler option.
userBox.add(User('Test User', 28));
TypeAdapterβ
Hive works with binary data. While it's entirely possible to write a custom adapter which fumbles with a βββββBinaryWriter and a BinaryReader,
it's much easier to let the βhive_generator
β package do the hard job for you. Making an adapter for specific class is then as simple as adding a few annotations.
Creating a TypeAdapter
import 'package:hive/hive.dart';
part 'user.g.dart';
()
class User {
(0)
final String name;
(1)
final int age;
User(this.name, this.age);
}
To generate TypeAdapter you should run flutter packages pub run build_runner build
. Thanks to the Makefile
scripts, we can do this with make generate-code
make watch-and-generate-code
until stopped will watch for file changes and automatically build code if necessary.
It's useful when dealing with a lot of code generation since it'll do a whole project build only at start and then do smaller builds only for affected files.
The created adapter must be registered.
Repositoriesβ
IHiveRepository
should be used with every repository that is using Hive.
Example
class UserRepository with IHiveRepository<User> implements IUserRepository {
String get boxKey => 'userInfoBoxKey';
Future<User?> getUser(String userKey) async {
return (await box).get(userKey);
}
Future<void> saveUser(String userKey, User user) async {
await (await box).put(userKey, user);
}
Future<void> deleteUser(String userKey) async {
await (await box).delete(userKey);
}
Dependency injectionβ
Dependency injection is an object-oriented technique that sends the dependencies of another object to an object. Using dependency injection, we can also move the creation and restriction of dependent objects outside the classes. This concept brings a more significant level of adaptability, decoupling, and simpler testing.
Popular choice managing service location is get_it.