Flutter本地数据存储与缓存管理插件hive_cache_manager的使用
Flutter本地数据存储与缓存管理插件hive_cache_manager的使用
特性
- 🤩️ 简单快速的编码
- ❤️ 使用hive进行缓存
- 🗂 使用flutter_secure_storage来存储加密密钥
- 📸 使用ValueListenableBuilder来监听数据变化
- 🥳 使存储自定义模型变得容易
通过使用此包,你无需为每个模型编写单独的Hive相关代码。该包提供了一个通用的缓存管理器类来处理Hive箱操作。
开始使用
在你的pubspec.yaml
文件中添加此包并运行pub get
:
dependencies:
hive_cache_manager: latest
引入库
import 'package:hive_cache_manager/hive_cache_manager.dart';
1. 创建自定义模型
假设我们想要存储关于书籍的信息。我们可以将 Dart 文件命名为book.dart
。
class Book {
String isbn;
String title;
String author;
int year;
//构造函数
Book({required this.title, required this.author,
required this.year, required this.isbn});
}
2. 使用hive注解并定义类型适配器文件的名称
这些步骤对于使用hive包是必要的。
- 使用
@HiveType
和@HiveField
注解。 - 在模型文件顶部添加
part 'model_file_name.g.dart';
。 - (model_file_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;
//构造函数
Book({required this.title, required this.author,
required this.year, required this.isbn});
}
3. 生成类型适配器文件
在你的pubspec.yaml
文件中添加build_runner
包作为开发依赖项:
dev_dependencies:
#代码生成
build_runner: latest
然后在终端中运行以下命令以生成Book类的类型适配器。这一步也是使用hive包所必需的。
flutter packages pub run build_runner build
这将在你的模型文件旁边创建model_file_name.g.dart
文件。
👍 不需要在你的pubspec.yaml
中添加hive_generator
包。hive_cache_manager已经包含了这个包。只需运行上述命令即可。
4. 扩展你的模型从IHiveModel
- IHiveModel是hive_cache_manager中的一个特殊抽象类。
- 当从这个类扩展时,你的模型必须重写
"mapKey"
计算属性。 - 如果你想用模型特定的键存储对象,可以使用这个属性来设置在保存模型对象到Hive箱时使用的键。
- 例如,我们可以选择ISBN号作为Hive箱中键值对的键。
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;
//构造函数
Book({required this.title, required this.author,
required this.year, required this.isbn});
//定义你的唯一键
@override
String get mapKey => isbn;
}
- 另外,你可以使用你的属性组合或任何字符串。
@override
String get mapKey => "$isbn - $title";
- 如果你想用自动递增的键存储你的对象,你可以返回一个空字符串(或任何字符串)。在这种情况下,这个属性将不会被使用。所以,你返回什么在这个mapKey中都不重要。
@override
String get mapKey => "";
5. 为你的模型创建一个缓存管理器类
ICacheManager<T extends IHiveModel>
是hive_cache_manager中的一个特殊抽象类。- 为了处理Hive箱操作,你需要为你的模型创建一个管理器类。
- 因为我们已经从IHiveModel扩展了我们的Book类,我们可以使用它代替T。
- 当从ICacheManager扩展时,
registerAdapters
方法必须被重写。- 在此方法中注册你生成的类型适配器类的对象。
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是Book类的type id
Hive.registerAdapter(BookAdapter()); // 如果未注册,这里注册生成的BookAdapter。
}
}
}
- 🎊 现在,
BookCacheManager
类可以处理所有如放入或删除Book对象等箱操作。 - 🎉
BookCacheManager
还提供了一个ValueListenableBuilder
,它连接到你放入Book对象的Hive箱。这样,你可以监听箱的变化而无需使用setState((){})。
6. 初始化Hive后使用
- 这一步也是使用hive包所必需的。
- 你可以在main中初始化它,然后在runApp之前调用。
import 'package:hive_flutter/hive_flutter.dart';
void main() async{
await Hive.initFlutter("hive_db");
runApp(const MyApp());
}
7. 创建一个管理器对象并显式调用其init方法
- init方法运行BookCacheManager的registerAdapters()方法,然后打开一个可以存储Book对象的Hive箱。
- 如果
isEncrypted
参数为true,则它会创建一个加密的箱,而无需你编写任何加密或flutter_secure_storage相关的代码。 - 如果你不希望加密数据,请使用
isEncrypted: false
。
BookCacheManager bookCacheManager = BookCacheManager("books_hive_box");
// 如果你想要一个加密的箱,传入true
await bookCacheManager.init(isEncrypted: true);
8. 创建一些模型对象
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',
);
- 🙋🏼♀️ 有任何其他《魔戒》粉丝吗?
9. 通过缓存管理器在Hive箱上执行任何操作
addItem
和addItems
方法使用自动递增的键添加值。putItem
和putItems
方法使用模型特定的键(使用mapKey
属性)添加值。
放入示例:
await bookCacheManager.putItem(item: firstBook);
await bookCacheManager.putItems(items: [firstBook, secondBook, thirdBook]);
// 使用mapKey属性访问一个项目
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);
添加示例:
List<Book> books = [firstBook, secondBook, thirdBook];
await bookCacheManager.addItems(items: books);
print("${bookCacheManager.getValues().first.isbn} 等于 9780618260515");
// 从Hive箱中删除名为 "thirdBook" 的对象
// 由于对象是用自动递增的键添加的,"thirdBook" 的键应该是2(第一个项目的键是0)
await bookCacheManager.removeItem(key: 2);
// 读取从0到1(包括1)的键的值
Iterable<Book> otherBooks = bookCacheManager.getValuesBetween(startKey: 0, endKey: 1);
// 将剩余的模型对象放入可迭代对象
Iterable<Book> remainingBooks = [firstBook, secondBook];
// "otherBooks" 和 "remainingBooks" 应该相等
// 覆盖Book类中的toString()方法以便打印漂亮的可迭代对象。
print("$otherBooks 等于 $remainingBooks");
10. 在UI上显示数据
以下是Example项目的屏幕录制。 App Bar上的 “+” 按钮向Hive箱添加3个Book对象。 借助ValueListenableBuilder,我们可以监听箱的变化。 Scaffold的body中使用三种不同的方式展示了箱中的数据。
- 第一个列表显示了箱中的所有数据。
- 第二个列表按键过滤(显示具有 “9780618260515” 和 “9780007136575” 键的书籍)。
- 第三个列表按模型类的属性过滤(仅显示年份信息为 “1955” 的书籍)。
✔️ 从一个列表中删除一个项目会被立即识别,并且更改会在所有列表中反映出来。
如何使用ValueListenableBuilder
通过缓存管理器的getValueListenableBuilder
方法访问ValueListenableBuilder。
bookCacheManager.getValueListenableBuilder(
buildLayout: buildBooksLayout,
keys: filterKeys,
)
此方法需要两个参数。第一个(buildLayout)是一个使用正在监听的数据的函数。以下是buildLayout参数的类型:
Widget Function(List<T> data) buildLayout
在示例项目中,它实现如下:
Widget buildBooksLayout(List<Book> books) {
// 在此处消费数据
// 在UI上显示数据并定义你的业务逻辑
return books.isEmpty
? const Center(child: Text("没有数据显示"))
: 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);
},
);
}
_BookCard
是一个定义Book对象UI布局的状态小部件。它使用Card和ListTile小部件。你可以创建任何你喜欢的设计/布局。查看GitHub上的 _BookCard
小部件以查看代码。
第二个参数控制按键过滤。这是一个可选参数。如果给定,箱中的数据将按给定的键过滤。只有过滤后的数据才会传递给buildLayout函数。
显示箱中的所有数据
不提供任何键以显示箱中的所有数据。
Container(
child: bookCacheManager.getValueListenableBuilder(
buildLayout: buildBooksLayout,
),
)
过滤特定书籍并显示它们
通过提供keys参数按键过滤。
Container(
child: bookCacheManager.getValueListenableBuilder(
buildLayout: buildBooksLayout,
keys: ["9780618260515", "9780007136575"], //《魔戒》第一部《护戒使者》和第三部《王者归来》的ISBN
),
)
或者,在自定义的ValueListenableBuilder小部件中创建自己的过滤器
使用缓存管理器的getListenable
方法获取ValueListenable。在构建方法中过滤或排序你的数据。
Container(
child: ValueListenableBuilder(
valueListenable: bookCacheManager.getListenable(),
builder: (context, box, widget) {
List<Book> data = [];
for (Book book in bookCacheManager.getValues()) {
// 过滤年份信息为1995的书籍
// 根据需要更改此过滤器
if (book.year == 1955) {
data.add(book);
}
}
// 你也可以在这里对数据进行排序
return buildLayout(data);
},
),
)
额外信息
- 此包依赖于flutter_secure_storage包以存储加密密钥。确保为所有平台(例如Web和Linux)进行所有必要的配置。
- 目前,flutter_secure_storage强制要求
minSdkVersion
大于等于18。 - 在使用flutter_secure_storage时,可能会遇到
compileSdkVersion
不兼容问题(它要求minSdkVersion >= 33
)。-
在你的gradle文件(/android/app/build.gradle)中相应地更改这些属性。对于Flutter 2.8或更高版本,请执行以下步骤:
- 在你的local.properties文件(/android/local.properties)中添加以下行:
flutter.compileSdkVersion=33 flutter.minSdkVersion=18
- 在你的gradle文件中引用新添加的版本号:
compileSdkVersion localProperties.getProperty('flutter.compileSdkVersion').toInteger() minSdkVersion localProperties.getProperty('flutter.minSdkVersion').toInteger()
-
更多关于Flutter本地数据存储与缓存管理插件hive_cache_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter本地数据存储与缓存管理插件hive_cache_manager的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter应用中使用hive_cache_manager
插件进行本地数据存储与缓存管理的代码示例。hive_cache_manager
结合了Hive的高性能本地存储和缓存管理功能,非常适合需要高效本地存储和缓存策略的应用。
首先,确保在pubspec.yaml
文件中添加依赖:
dependencies:
flutter:
sdk: flutter
hive: ^2.0.4 # 请检查最新版本
hive_flutter: ^1.0.0 # 如果你需要在Flutter中使用Hive的Widget
hive_cache_manager: ^0.3.0 # 请检查最新版本
然后,运行flutter pub get
来安装这些依赖。
初始化Hive和CacheManager
在你的应用入口文件(通常是main.dart
)中,初始化Hive和CacheManager:
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_cache_manager/hive_cache_manager.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化Hive
await Hive.initFlutter();
// 打开一个box用于存储数据
var box = await Hive.openBox('myBox');
// 初始化CacheManager,配置Hive存储
CacheManager cacheManager = HiveCacheManager(
config: CacheConfig(
store: box,
maxAge: const Duration(days: 7), // 缓存数据的最大存活时间
keyBuilder: (url) => url.hashCode.toString(), // 用于生成缓存键的策略
),
);
runApp(MyApp(cacheManager: cacheManager));
}
class MyApp extends StatelessWidget {
final CacheManager cacheManager;
MyApp({required this.cacheManager});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('HiveCacheManager Demo')),
body: Center(
child: MyHomePage(cacheManager: cacheManager),
),
),
);
}
}
使用CacheManager获取和缓存数据
在你的主页组件中,你可以使用CacheManager来获取和缓存网络数据:
import 'package:flutter/material.dart';
import 'package:hive_cache_manager/hive_cache_manager.dart';
class MyHomePage extends StatefulWidget {
final CacheManager cacheManager;
MyHomePage({required this.cacheManager});
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<String?>? _futureData;
@override
void initState() {
super.initState();
_fetchData();
}
Future<void> _fetchData() async {
String url = 'https://jsonplaceholder.typicode.com/posts/1'; // 示例API
try {
// 使用CacheManager获取数据,如果缓存中有数据则直接返回缓存
var response = await widget.cacheManager.getFile(url);
String data = await response.readAsString();
setState(() {
_futureData = Future.value(data);
});
} catch (error) {
setState(() {
_futureData = Future.error(error);
});
}
}
@override
Widget build(BuildContext context) {
return FutureBuilder<String?>(
future: _futureData,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else if (snapshot.hasData) {
return Text('Data: ${snapshot.data!}');
}
}
return CircularProgressIndicator();
},
);
}
}
总结
上面的代码展示了如何在Flutter应用中使用hive_cache_manager
进行本地数据存储与缓存管理。首先,我们初始化了Hive和CacheManager,然后在组件中使用CacheManager来获取和缓存网络数据。这样,应用可以高效地管理本地缓存,提高用户体验。
请确保在实际应用中根据需求调整缓存配置,如缓存的过期时间、缓存键的生成策略等。