Flutter数据存储管理插件entity_store的使用
Flutter数据存储管理插件EntityStore的使用
简介
EntityStore通过围绕实体进行状态管理来增强Flutter应用开发。该库将应用的业务逻辑封装在不可变实体中,并通过集中式状态管理保持UI的一致性。
以下TodoTile组件示例演示了EntityStore如何连接UI组件与它们的状态。
class TodoTile extends StatelessWidget {
// ...
@override
Widget build(BuildContext context) {
// 监控特定的Todo
final todo = context.watchOne<int, Todo>(todoId)!;
// 切换Todo的完成状态
return CheckboxListTile(
title: Text(todo.name),
value: todo.isDone,
onChanged: (bool? value) {
if (value != null) {
todoRepository.save(todo.toggle());
}
},
);
}
}
特点
- 反应式UI同步:EntityStore会根据状态变化在UI上做出反应。例如,在上述代码示例中,
watchOne
方法用于监控特定的Todo实体,并在状态变化时更新复选框显示。 - 简洁的状态更新:实体的状态仅在必要时通过新实例进行更新。通过调用
todo.toggle()
来切换Todo的完成状态,并通过仓库持久化结果。 - 中心处理实体:EntityStore专注于构成应用核心部分的实体,使开发者能够专注于业务逻辑。
- 灵活的数据库集成:EntityStore有助于与外部数据源集成。通过替换仓库实现,可以连接到Firebase Firestore、本地数据库或其他存储。
- 减少样板代码:使用预先准备好的仓库实现消除了开发者编写重复数据库操作代码的需求。这加速了开发过程并简化了应用的维护。
安装
要在您的Flutter项目中引入EntityStore包,请在pubspec.yaml
文件中添加以下内容:
dependencies:
entity_store: latest_version
使用
以下示例代码演示了如何使用EntityStore实现一个Todo应用。
Todo实体的定义
实体封装了应用的核心业务逻辑,并具有唯一的标识符(ID)。这使得在整个应用中可以识别实体,保持数据完整性。在EntityStore中,实体被设计为不可变的。这对于检测实体状态的变化并确保其在UI中正确反映非常重要。
Todo
类是一个实现了这一概念的例子。每个Todo
项都有一个唯一的ID、名称和完成状态属性。create
工厂方法允许您创建一个新的Todo
实例,并随机生成名称。toggle
方法用于切换Todo
的完成状态,返回一个带有更新状态的新Todo
实例。
class Todo implements Entity<int> {
// 实体属性必须是不可变的。
@override
final int id;
final String name;
final bool isDone;
Todo(this.id, this.name, this.isDone);
// 创建新的Todo实体
factory Todo.create(int id) {
return Todo(
id,
getRandomTodoName(),
false,
);
}
// 切换Todo的完成状态
Todo toggle() {
return Todo(
id,
name,
!isDone,
);
}
}
这种不可变的设计方法允许每个Todo
实例可重用,并且只能通过创建新实例来更改状态,防止意外副作用,使状态管理更加可预测。它还减少了检测实体变化和更新UI时的复杂性,提高了应用的可维护性。
Todo仓库的实现
EntityStore的一个强大功能是实现了仓库模式。遵循此模式,TodoRepository
继承自LocalStorageRepository
,并通过覆盖继承的方法定义自己的保存、读取和删除实体的方式。
TodoRepository
是LocalStorageRepository
的一个特定实现,用于Todo
实体。它覆盖了fromJson
和toJson
方法,以便于从JSON数据读取和保存实体,从而便于在实体和数据存储之间转换。
class TodoRepository extends LocalStorageRepository<int, Todo> {
TodoRepository(super.controller, super.localStorageHandler);
@override
Todo fromJson(Map<String, dynamic> json) {
// 从JSON创建一个Todo实体
}
@override
Map<String, dynamic> toJson(Todo entity) {
// 将一个Todo实体转换为JSON
}
}
关于LocalStorageHandler
EntityStore包默认提供了InMemoryStorageHandler
,这是一个简单的存储处理器,仅在内存中存储数据。这使得开发和测试期间的状态管理变得容易。但在实际应用中,您可以实现自定义的LocalStorageHandler
以将数据存储在设备的本地存储中。
class InMemoryStorageHandler extends LocalStorageHandler {
// 在内存中进行数据操作
}
EntityStore的设置
要设置EntityStore,初始化EntityStoreNotifier
或EntityStoreController
,并与仓库关联如下:
final entityStoreNotifier = EntityStoreNotifier();
final entityStoreController = EntityStoreController(entityStoreNotifier);
final storageHandler = InMemoryStorageHandler();
final todoRepository = TodoRepository(entityStoreController, storageHandler);
虽然上述代码片段为了简单起见使用了全局变量,但建议使用依赖注入(DI),例如使用Riverpod的Provider
或GetIt。这样做可以有效地解析应用不同部分所需的依赖关系,提高测试性和代码的可重用性。
示例:
final entityStoreProvider = Provider((ref) => EntityStoreNotifier());
final entityStoreControllerProvider = Provider((ref) => EntityStoreController(ref.watch(entityStoreProvider)));
// ...
// 在应用的其他部分
final entityStoreNotifier = ref.watch(entityStoreProvider);
final entityStoreController = ref.watch(entityStoreControllerProvider);
采用这种方法,可以使应用各个部分所需的各种依赖关系更加明确,并实现一种能应对变化和扩展的设计。
在UI中的使用
设置EntityStoreProviderScope
在使用EntityStore包的第一步是在应用的顶层设置一个EntityStoreProviderScope
。这为整个应用范围内的状态监控和共享奠定了基础。
class MyApp extends StatelessWidget {
// ...
@override
Widget build(BuildContext context) {
// 在应用根部放置EntityStoreProviderScope
return EntityStoreProviderScope(
entityStoreNotifier: entityStoreNotifier,
child: MaterialApp(
// ...
),
);
}
}
监控状态并更新UI
您可以使用selectAll
来获取所有Todo实体的ID,并在UI中作为列表显示。这样,您可以监控整个Todo列表,并在有新的Todo添加时更新列表。
context.watchOne
监控特定的实体。通过利用这些方法,状态的变化会自动反映在UI中。
class MyHomePage extends StatefulWidget {
// ...
@override
Widget build(BuildContext context) {
// 获取所有Todos的ID
final todoIds = context.selectAll<int, Todo, List<int>>(
(value) => value.ids.toList(),
);
// ...
}
}
执行实体操作并保持UI一致性
当您通过仓库操作实体时,EntityStore
中的状态会被更新,相关的UI组件也会自动更新。
class TodoTile extends StatelessWidget {
// ...
@override
Widget build(BuildContext context) {
// 监控特定的Todo
final todo = context.watchOne<int, Todo>(todoId);
// 切换Todo的完成状态
return CheckboxListTile(
title: Text(todo.name),
value: todo.isDone,
onChanged: (bool? value) {
if (value != null) {
// 通过仓库更新实体
todoRepository.save(todo.toggle());
}
},
);
}
}
状态管理方法的详细说明和使用示例
EntityStore提供的watch
、select
和read
方法是监视应用状态并相应地更新UI的重要工具。这些方法帮助保持EntityStore管理和UI组件之间的同步。
watch
方法的使用
您可以使用watchAll
方法实时监控未完成的Todo,并在发生变化时更新列表。
final activeTodos = context.watchAll<int, Todo>(
(todo) => !todo.isDone,
);
ListView.builder(
itemCount: activeTodos.length,
itemBuilder: (context, index) {
final todo = activeTodos.values.elementAt(index);
return ListTile(
title: Text(todo.name),
leading: Checkbox(
value: todo.isDone,
onChanged: (bool? checked) {
// 逻辑以更新Todo的完成状态
},
),
);
},
);
您可以使用watchOne
方法来监控特定Todo实体的状态变化,并仅更新那个Todo。
final todo = context.watchOne<int, Todo>(todoId);
if (todo != null) {
return CheckboxListTile(
title: Text(todo.name),
value: todo.isDone,
onChanged: (bool? newValue) {
// 逻辑以更新Todo的状态
},
);
}
select
方法的使用
您可以使用selectAll
方法从整个Todo列表中检索特定数据(例如名称)并仅显示那些数据。
final todoNames = context.selectAll<int, Todo, List<String>>(
(todos) => todos.values.map((todo) => todo.name).toList(),
);
ListView(
children: todoNames.map((name) => Text(name)).toList(),
);
您可以使用selectOne
方法从单个Todo中检索特定数据,并在Todo的名称发生变化时更新显示该数据的小部件。
final todoName = context.selectOne<int, Todo, String>(
todoId,
(todo) => todo.name,
);
Text(todoName ?? 'No name');
read
方法的使用
您可以使用readAll
方法在屏幕初始加载时一次性检索所有Todos,并在不触发重建的情况下使用数据。
final allTodos = context.readAll<int, Todo>();
// 在初始加载时显示所有Todos
ListView(
children: allTodos.values.map((todo) => Text(todo.name)).toList(),
);
您可以使用readOne
方法基于用户操作执行一次性数据读取,例如在对话框中显示Todo详情。
final todo = context.readOne<int, Todo>(todoId);
// 显示由用户操作触发的对话框
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(todo?.name ?? 'No name'),
content: Text('已完成: ${todo?.isDone}'),
);
},
);
通过使用这些方法,您可以高效地读取和更新EntityStore中的状态,同时确保应用状态的变化能够在UI中按需反映。
仓库的使用
仓库旨在抽象数据源操作并将业务逻辑与数据访问代码分离。在EntityStore中,通过仓库执行的实体操作会自动反映在UI中。这意味着当您通过仓库保存、更新或删除实体时,这些更改会自动传播到UI,允许用户立即看到最新的状态。
这种行为是通过使用反应式方法(如watch
、select
等)结合EntityStore实现的,确保EntityStore管理和UI组件之间的同步。以下是基本的仓库操作及其使用示例。
findById
获取指定ID的实体。
// 示例:通过ID查找Todo
var result = await todoRepository.findById(todoId);
if (result.isOk) {
var todo = result.ok;
// 执行Todo相关操作
}
findAll
检索所有实体。
// 示例:获取满足特定条件的所有Todos
var result = await todoRepository.query()
.where('isComplete', isEqualTo: false)
.findAll();
if (result.isOk) {
var todos = result.ok;
// 执行Todos列表上的操作
}
findOne
检索符合特定条件的第一个实体。
// 示例:查找符合特定条件的第一个Todo
var result = await todoRepository.query()
.where('isComplete', isEqualTo: false)
.findOne();
if (result.isOk) {
var todo = result.ok;
// 执行Todo相关操作
}
count
计算符合特定条件的实体数量。
// 示例:计算未完成的Todos数量
var result = await todoRepository.query()
.where('isComplete', isEqualTo: false)
.count();
if (result.isOk) {
var activeCount = result.ok;
// 使用activeCount执行操作
}
save
保存或更新一个实体。
// 示例:保存一个新Todo
var newTodo = Todo.create(name: '新任务');
var result = await todoRepository.save(newTodo);
if (result.isOk) {
// 处理保存操作的成功
}
delete
删除一个实体。
// 示例:删除一个Todo
var result = await todoRepository.delete(todoId);
if (result.isOk) {
// 处理删除操作的成功
}
upsert
如果实体不存在则创建,如果存在则更新。
// 示例:Upsert一个Todo
var result = await todoRepository.upsert(
todoId,
creater: () => Todo.create(name: '新任务'),
updater: (existingTodo) => existingTodo.copyWith(isComplete: true),
);
if (result.isOk) {
// 处理Upsert操作的成功
}
更多关于Flutter数据存储管理插件entity_store的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据存储管理插件entity_store的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
entity_store
是一个用于 Flutter 应用的数据存储管理插件,它提供了一种简单且高效的方式来管理应用中的数据实体。通过 entity_store
,你可以轻松地进行数据的增删改查操作,并且它还支持数据的变化监听和状态管理。
安装
首先,你需要在 pubspec.yaml
文件中添加 entity_store
依赖:
dependencies:
flutter:
sdk: flutter
entity_store: ^0.1.0 # 请根据最新版本进行更新
然后运行 flutter pub get
来安装依赖。
基本用法
1. 创建实体
首先,你需要定义你的数据实体类。这个类通常会包含一些属性和方法。
class User {
final String id;
final String name;
final int age;
User({required this.id, required this.name, required this.age});
// 实现 toString 方法方便调试
@override
String toString() => 'User(id: $id, name: $name, age: $age)';
}
2. 创建实体存储
接下来,你可以创建一个 EntityStore
实例来管理 User
实体。
import 'package:entity_store/entity_store.dart';
final entityStore = EntityStore<String, User>();
这里的 String
是实体的唯一标识符类型,User
是实体类型。
3. 添加实体
你可以使用 add
方法将实体添加到存储中。
final user = User(id: '1', name: 'Alice', age: 25);
entityStore.add(user);
4. 获取实体
你可以通过 get
方法获取单个实体,或者通过 getAll
方法获取所有实体。
final user = entityStore.get('1');
print(user); // User(id: 1, name: Alice, age: 25)
final allUsers = entityStore.getAll();
print(allUsers); // {1: User(id: 1, name: Alice, age: 25)}
5. 更新实体
你可以使用 update
方法来更新实体。
entityStore.update(User(id: '1', name: 'Alice', age: 26));
6. 删除实体
你可以使用 remove
方法来删除实体。
entityStore.remove('1');
7. 监听数据变化
entity_store
支持监听实体的变化。你可以使用 stream
来监听特定实体的变化,或者使用 streamAll
来监听所有实体的变化。
entityStore.stream('1').listen((user) {
print('User updated: $user');
});
entityStore.streamAll().listen((users) {
print('All users: $users');
});
高级用法
1. 自定义存储
你可以通过继承 EntityStore
来创建自定义的存储类,以便在其中添加更多的业务逻辑。
class UserStore extends EntityStore<String, User> {
// 添加自定义方法或重写现有方法
}