Flutter数据持久化插件flutter_data的使用
Flutter数据持久化插件flutter_data的使用
Flutter Data 是一个强大的数据框架,旨在为 Flutter 应用提供零样板代码的持久化和反应式模型。本文将介绍如何使用 flutter_data
插件进行数据持久化,并提供完整的示例 Demo。
特性
- 离线优先:基于 Hive 的本地存储,支持失败处理和重试 API。
- 直观的 API 和简单的设置:通过 Dart mixins 和代码生成器实现可配置和可组合。
- 强大的关系支持:自动同步的关系图和反应式关系。
快速开始
设置和初始化
首先,在 pubspec.yaml
文件中添加依赖:
dependencies:
flutter:
sdk: flutter
flutter_data: ^<latest_version>
riverpod: ^<latest_version>
dev_dependencies:
build_runner: ^<latest_version>
json_serializable: ^<latest_version>
然后运行以下命令安装依赖:
flutter pub get
接下来,创建一个模型类并使用 @DataRepository
注解:
import 'package:flutter_data/flutter_data.dart';
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart'; // 这个文件会自动生成
@JsonSerializable()
@DataRepository([MyJSONServerAdapter])
class User extends DataModel<User> {
@override
final int? id; // ID 可以是任何类型
final String name;
User({this.id, required this.name});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
mixin MyJSONServerAdapter on RemoteAdapter<User> {
@override
String get baseUrl => "https://my-json-server.typicode.com/flutterdata/demo/";
}
运行代码生成器:
flutter pub run build_runner build
使用 Repository
在 Widget 中使用 ref.users
来访问 Repository:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'user.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(usersProvider.watchOne(1));
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Flutter Data Example')),
body: Center(
child: state.when(
data: (user) => Text(user!.name),
loading: () => CircularProgressIndicator(),
error: (err, stack) => Text('Error: $err'),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await ref.read(usersProvider).save(User(id: 1, name: 'Updated'));
},
child: Icon(Icons.update),
),
),
);
}
}
更多示例
创建新用户
final user = await User(name: 'New User').save();
print(user.id); // 新用户的ID
查找用户
final user = await ref.users.findOne(1, params: {'_embed': 'tasks'});
print(user.tasks.length); // 用户的任务数量
删除任务
await user.tasks.last.delete();
完整示例 Demo
以下是完整示例 Demo,包含基本的增删改查操作:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_data/flutter_data.dart';
import 'models/user.dart';
const List<int> _encryptionKey = [
146, 54, 40, 58, 46, 90, 152, 2, 193, 210, 220, 199, 16, 96, 107, 4,
243, 133, 171, 31, 241, 26, 149, 53, 172, 36, 121, 103, 17, 155, 120, 61
];
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends ConsumerStatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends ConsumerState<HomeScreen> {
late Directory _dir;
@override
void initState() {
super.initState();
initStorage();
}
Future<void> initStorage() async {
final container = ProviderContainer(
overrides: [
configureRepositoryLocalStorage(
baseDirFn: () => _dir.path,
encryptionKey: _encryptionKey,
clear: LocalStorageClearStrategy.always,
),
],
);
_dir = Directory.systemTemp.createTempSync();
print('Using temporary directory: ${_dir.path}');
_dir.deleteSync(recursive: true);
await container.read(repositoryInitializerProvider.future);
container.users.logLevel = 2;
container.tasks.logLevel = 2;
await container.tasks.findAll(params: {'user_id': 1, '_limit': 3});
final user = User(id: 19, name: 'Zeku');
final user2 = await container.users.findOne(19, remote: false);
assert(user == user2);
assert(user.tasks.length == 3);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Flutter Data Example')),
body: Center(
child: Text('Check console for logs.'),
),
);
}
@override
void dispose() {
_dir.deleteSync(recursive: true);
super.dispose();
}
}
通过上述步骤,您可以轻松地在 Flutter 应用中集成 flutter_data
插件,实现数据持久化和离线优先的功能。更多详细信息请参考 官方文档。
更多关于Flutter数据持久化插件flutter_data的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据持久化插件flutter_data的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用 flutter_data
插件进行 Flutter 数据持久化的代码示例。flutter_data
是一个强大的 Flutter 库,它简化了从远程 API 获取数据并将其本地持久化到设备存储(通常是 SQLite)的过程。
首先,确保你的 pubspec.yaml
文件中包含了 flutter_data
依赖:
dependencies:
flutter:
sdk: flutter
flutter_data: ^0.x.y # 请替换为最新版本号
json_annotation: ^4.0.0 # flutter_data 通常依赖于此
然后运行 flutter pub get
来获取依赖。
接下来,设置你的数据模型。假设我们有一个简单的用户模型:
import 'package:flutter_data/flutter_data.dart';
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@DataModel()
class User with DataModelMixin {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
// 从 JSON 反序列化
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
// 序列化到 JSON
Map<String, dynamic> toJson() => _$UserToJson(this);
}
// 生成 DataModel 相关的代码
@generateDataModel(classes: [User])
然后,你需要创建一个数据仓库(DataRepository),它定义了如何远程获取数据和本地存储数据。flutter_data
通常与 hive
或 sembast
一起使用进行本地存储,但这里我们主要关注它的远程数据获取和本地缓存功能。
创建一个配置类来设置你的远程 API 端点:
import 'package:flutter_data/flutter_data.dart';
import 'package:http/http.dart' as http;
class MyRemoteAdapter extends RemoteAdapter<User> {
@override
String get baseUrl => 'https://jsonplaceholder.typicode.com'; // 示例 API
@override
Future<List<User>> fetchAll(DataQuery<User> query) async {
final response = await http.get(Uri.parse('$baseUrl/users'));
if (response.statusCode == 200) {
final List<dynamic> body = jsonDecode(response.body);
return body.map((dynamic item) => User.fromJson(item)).toList();
} else {
throw Exception('Failed to load users');
}
}
@override
Future<User?> fetchOne(int id) async {
final response = await http.get(Uri.parse('$baseUrl/users/$id'));
if (response.statusCode == 200) {
final Map<String, dynamic> body = jsonDecode(response.body);
return User.fromJson(body);
} else {
throw Exception('Failed to load user $id');
}
}
}
在你的应用中配置 flutter_data
:
import 'package:flutter/material.dart';
import 'package:flutter_data/flutter_data.dart';
import 'user.dart'; // 导入你的数据模型
import 'my_remote_adapter.dart'; // 导入你的远程适配器
void main() {
runApp(
DataRepositoryProvider(
repos: [
DataRepository<User>(
adapter: MyRemoteAdapter(),
// 可选:配置本地存储,这里使用内存存储作为示例
localAdapter: MemoryDataAdapter<User>(),
),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Flutter Data Example')),
body: UserListScreen(),
),
);
}
}
最后,创建一个屏幕来显示用户列表:
import 'package:flutter/material.dart';
import 'package:flutter_data/flutter_data.dart';
import 'user.dart';
class UserListScreen extends StatefulWidget {
@override
_UserListScreenState createState() => _UserListScreenState();
}
class _UserListScreenState extends State<UserListScreen> {
late final DataRepository<User> usersRepository;
@override
void initState() {
super.initState();
usersRepository = DataRepositoryProvider.of<User>(context)!;
// 预加载所有用户
usersRepository.watchAll();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('User List')),
body: FutureBuilder<List<User>>(
future: usersRepository.findAll(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error!}'));
} else {
final users = snapshot.data ?? [];
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
},
);
}
},
),
);
}
}
这个示例展示了如何使用 flutter_data
插件从远程 API 获取用户数据并将其本地持久化。请注意,实际项目中你可能需要更复杂的错误处理和状态管理。此外,根据你的需求,你可能还需要配置本地存储适配器(如 HiveDataAdapter
或 SembastDataAdapter
)来替代内存存储。