【Flutter x 鸿蒙】第六篇:状态管理、数据持久化与分布式数据
在掌握了Flutter与鸿蒙的导航和多设备适配后,今天我们深入探讨状态管理 、数据持久化 和鸿蒙分布式数据这三个核心主题。这些技术是构建复杂、高性能Flutter应用的基础,也是充分利用鸿蒙分布式特性的关键。
一、Flutter状态管理方案选型
1.1 状态管理方案对比
在Flutter开发中,选择合适的方案至关重要。以下是主流方案的对比:
| 方案 | 适用场景 | 学习曲线 | 性能表现 | 代码量 |
|---|---|---|---|---|
| Provider | 中小型应用,简单状态共享 | 低 | 优秀 | 少 |
| Riverpod | 中大型应用,复杂状态管理 | 中 | 优秀 | 中等 |
| Bloc/Cubit | 大型应用,复杂业务逻辑 | 中高 | 优秀 | 较多 |
| GetX | 快速开发,全功能框架 | 低 | 优秀 | 少 |
| MobX | 响应式状态管理 | 中 | 优秀 | 中等 |
1.2 Provider实战:计数器应用
Provider是Flutter官方推荐的状态管理方案,简单易用:
// lib/models/counter_model.dart
import 'package:flutter/foundation.dart';
class CounterModel with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void decrement() {
_count--;
notifyListeners();
}
}
// lib/pages/counter_page.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/counter_model.dart';
class CounterPage extends StatelessWidget {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('计数器')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('当前计数:'),
Consumer<CounterModel>(
builder: (context, counter, child) {
return Text(
'${counter.count}',
style: Theme.of(context).textTheme.headlineMedium,
);
},
),
],
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () => context.read<CounterModel>().increment(),
child: const Icon(Icons.add),
),
const SizedBox(height: 8),
FloatingActionButton(
onPressed: () => context.read<CounterModel>().decrement(),
child: const Icon(Icons.remove),
),
],
),
);
}
}
1.3 Riverpod实战:用户信息管理
Riverpod是Provider的升级版,更加强大和灵活:
// lib/providers/user_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
final userProvider = StateNotifierProvider<UserNotifier, UserState>((ref) {
return UserNotifier();
});
class UserState {
final String? name;
final String? email;
final bool isLoading;
UserState({
this.name,
this.email,
this.isLoading = false,
});
UserState copyWith({
String? name,
String? email,
bool? isLoading,
}) {
return UserState(
name: name ?? this.name,
email: email ?? this.email,
isLoading: isLoading ?? this.isLoading,
);
}
}
class UserNotifier extends StateNotifier<UserState> {
UserNotifier() : super(UserState());
Future<void> loadUser() async {
state = state.copyWith(isLoading: true);
// 模拟网络请求
await Future.delayed(const Duration(seconds: 1));
state = state.copyWith(
name: '张三',
email: 'zhangsan@example.com',
isLoading: false,
);
}
void updateName(String name) {
state = state.copyWith(name: name);
}
void clearUser() {
state = UserState();
}
}
二、数据持久化方案
2.1 SharedPreferences:简单键值存储
// lib/services/local_storage_service.dart
import 'package:shared_preferences/shared_preferences.dart';
class LocalStorageService {
static late SharedPreferences _prefs;
static Future<void> init() async {
_prefs = await SharedPreferences.getInstance();
}
// 保存数据
static Future<bool> saveString(String key, String value) {
return _prefs.setString(key, value);
}
static Future<bool> saveInt(String key, int value) {
return _prefs.setInt(key, value);
}
static Future<bool> saveBool(String key, bool value) {
return _prefs.setBool(key, value);
}
// 读取数据
static String getString(String key, [String defaultValue = '']) {
return _prefs.getString(key) ?? defaultValue;
}
static int getInt(String key, [int defaultValue = 0]) {
return _prefs.getInt(key) ?? defaultValue;
}
static bool getBool(String key, [bool defaultValue = false]) {
return _prefs.getBool(key) ?? defaultValue;
}
// 删除数据
static Future<bool> remove(String key) {
return _prefs.remove(key);
}
static Future<bool> clear() {
return _prefs.clear();
}
}
2.2 Hive:高性能NoSQL数据库
Hive是轻量级、高性能的键值数据库:
# pubspec.yaml
dependencies:
hive: ^2.2.3
hive_flutter: ^1.1.0
path_provider: ^2.0.15
// lib/services/hive_service.dart
import 'package:hive_flutter/hive_flutter.dart';
import 'package:path_provider/path_provider.dart';
class HiveService {
static const String userBox = 'user_box';
static const String settingsBox = 'settings_box';
static Future<void> init() async {
final appDocumentDir = await getApplicationDocumentsDirectory();
Hive.init(appDocumentDir.path);
// 注册适配器(如果需要存储自定义对象)
// Hive.registerAdapter(UserAdapter());
await Hive.openBox(userBox);
await Hive.openBox(settingsBox);
}
// 保存数据
static Future<void> saveUserData(String key, dynamic value) async {
final box = Hive.box(userBox);
await box.put(key, value);
}
// 读取数据
static dynamic getUserData(String key) {
final box = Hive.box(userBox);
return box.get(key);
}
// 删除数据
static Future<void> deleteUserData(String key) async {
final box = Hive.box(userBox);
await box.delete(key);
}
// 清空数据
static Future<void> clearUserData() async {
final box = Hive.box(userBox);
await box.clear();
}
}
2.3 SQLite:关系型数据库
对于复杂的数据结构,SQLite是更好的选择:
# pubspec.yaml
dependencies:
sqflite: ^2.3.0
path: ^1.8.3
// lib/services/database_service.dart
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseService {
static Database? _database;
static Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
static Future<Database> _initDatabase() async {
final databasePath = await getDatabasesPath();
final path = join(databasePath, 'app_database.db');
return openDatabase(
path,
version: 1,
onCreate: (db, version) async {
await db.execute('''
CREATE TABLE users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL,
created_at INTEGER NOT NULL
)
''');
await db.execute('''
CREATE TABLE settings(
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT NOT NULL,
value TEXT NOT NULL,
created_at INTEGER NOT NULL
)
''');
},
);
}
// 插入用户
static Future<int> insertUser(Map<String, dynamic> user) async {
final db = await database;
return db.insert('users', user);
}
// 查询用户
static Future<List<Map<String, dynamic>>> getUsers() async {
final db = await database;
return db.query('users');
}
// 更新用户
static Future<int> updateUser(int id, Map<String, dynamic> user) async {
final db = await database;
return db.update('users', user, where: 'id = ?', whereArgs: [id]);
}
// 删除用户
static Future<int> deleteUser(int id) async {
final db = await database;
return db.delete('users', where: 'id = ?', whereArgs: [id]);
}
}
三、鸿蒙分布式数据同步
3.1 分布式数据管理原理
鸿蒙的分布式数据管理(Distributed Data Management, DDM)允许应用在不同设备间同步数据,实现无缝的跨设备体验。
3.2 分布式键值存储
// lib/services/distributed_kv_service.dart
import 'package:flutter/services.dart';
class DistributedKVService {
static const MethodChannel _channel =
MethodChannel('com.example/distributed_kv');
// 保存数据到分布式存储
static Future<bool> save(String key, String value) async {
try {
final result = await _channel.invokeMethod('save', {
'key': key,
'value': value,
});
return result == true;
} catch (e) {
return false;
}
}
// 从分布式存储读取数据
static Future<String?> get(String key) async {
try {
final result = await _channel.invokeMethod('get', {'key': key});
return result as String?;
} catch (e) {
return null;
}
}
// 删除分布式存储中的数据
static Future<bool> delete(String key) async {
try {
final result = await _channel.invokeMethod('delete', {'key': key});
return result == true;
} catch (e) {
return false;
}
}
// 监听数据变化
static Stream<String> get dataChangeStream {
return _channel.receiveBroadcastStream().map((event) {
return event.toString();
});
}
}
3.3 鸿蒙端分布式KV实现
// ohos/entry/src/main/ets/services/DistributedKVService.ts
import common from '@ohos.app.ability.common';
import distributed from '@ohos.distributed';
import { BusinessError } from '@ohos.base';
export class DistributedKVService {
private context: common.UIAbilityContext;
private channel: any;
private kvManager: any;
private kvStore: any;
private eventSink: any;
constructor(context: common.UIAbilityContext) {
this.context = context;
this.initChannel();
this.initKVStore();
}
private initChannel() {
this.channel = new MethodChannel(
this.context,
'com.example/distributed_kv',
StandardMethodCodec.INSTANCE
);
this.channel.setMethodCallHandler(this.handleMethodCall.bind(this));
// EventChannel用于数据变化监听
const eventChannel = new EventChannel(
this.context,
'com.example/distributed_kv',
StandardMessageCodec.INSTANCE
);
eventChannel.setStreamHandler({
onListen: (args: any, events: any) => {
this.eventSink = events;
},
onCancel: (args: any) => {
this.eventSink = undefined;
}
});
}
private async initKVStore() {
try {
// 创建KVManager
this.kvManager = distributed.createKVManager({
context: this.context,
bundleName: 'com.example.app'
});
// 创建KVStore
this.kvStore = await this.kvManager.getKVStore('app_data', {
createIfMissing: true
});
// 监听数据变化
this.kvStore.on('dataChange', (data: any) => {
if (this.eventSink) {
this.eventSink.success(`数据变化: ${JSON.stringify(data)}`);
}
});
} catch (error) {
console.error('初始化KVStore失败:', error);
}
}
private async handleMethodCall(call: any, result: any) {
switch (call.method) {
case 'save':
await this.saveData(call.arguments, result);
break;
case 'get':
await this.getData(call.arguments, result);
break;
case 'delete':
await this.deleteData(call.arguments, result);
break;
default:
result.notImplemented();
}
}
private async saveData(args: any, result: any) {
try {
const key = args.key;
const value = args.value;
await this.kvStore.put(key, value);
result.success(true);
} catch (error) {
result.error('保存数据失败', error.message);
}
}
private async getData(args: any, result: any) {
try {
const key = args.key;
const value = await this.kvStore.get(key);
result.success(value);
} catch (error) {
result.error('获取数据失败', error.message);
}
}
private async deleteData(args: any, result: any) {
try {
const key = args.key;
await this.kvStore.delete(key);
result.success(true);
} catch (error) {
result.error('删除数据失败', error.message);
}
}
}
3.4 分布式对象存储
对于复杂对象,可以使用分布式对象存储:
// lib/services/distributed_object_service.dart
import 'package:flutter/services.dart';
import 'dart:convert';
class DistributedObjectService {
static const MethodChannel _channel =
MethodChannel('com.example/distributed_object');
// 保存对象
static Future<bool> saveObject(String key, Map<String, dynamic> object) async {
try {
final result = await _channel.invokeMethod('saveObject', {
'key': key,
'value': json.encode(object),
});
return result == true;
} catch (e) {
return false;
}
}
// 获取对象
static Future<Map<String, dynamic>?> getObject(String key) async {
try {
final result = await _channel.invokeMethod('getObject', {'key': key});
if (result != null) {
return json.decode(result as String);
}
return null;
} catch (e) {
return null;
}
}
// 监听对象变化
static Stream<Map<String, dynamic>> get objectChangeStream {
return _channel.receiveBroadcastStream().map((event) {
return json.decode(event as String);
});
}
}
四、状态管理最佳实践
4.1 状态分层架构
将状态按照作用域进行分层管理:
// 应用级状态
final appConfigProvider = StateNotifierProvider<AppConfigNotifier, AppConfig>((ref) {
return AppConfigNotifier();
});
// 页面级状态
final homePageProvider = StateNotifierProvider<HomePageNotifier, HomePageState>((ref) {
return HomePageNotifier();
});
// 组件级状态
final counterProvider = StateProvider<int>((ref) => 0);
4.2 状态持久化策略
结合Riverpod和Hive实现状态持久化:
// lib/providers/persistent_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/hive_flutter.dart';
final persistentCounterProvider = StateNotifierProvider<PersistentCounterNotifier, int>((ref) {
return PersistentCounterNotifier();
});
class PersistentCounterNotifier extends StateNotifier<int> {
PersistentCounterNotifier() : super(0) {
_loadFromStorage();
}
Future<void> _loadFromStorage() async {
final value = HiveService.getUserData('counter') ?? 0;
state = value;
}
void increment() {
state++;
_saveToStorage();
}
void decrement() {
state--;
_saveToStorage();
}
Future<void> _saveToStorage() async {
await HiveService.saveUserData('counter', state);
}
}
4.3 状态恢复机制
在应用启动时恢复状态:
// lib/main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化数据存储
await HiveService.init();
// 恢复应用状态
final savedCounter = HiveService.getUserData('counter') ?? 0;
runApp(ProviderScope(
overrides: [
persistentCounterProvider.overrideWithValue(
PersistentCounterNotifier()..state = savedCounter,
),
],
child: MyApp(),
));
}
五、实战案例:跨设备待办事项应用
让我们实现一个完整的跨设备待办事项应用,展示状态管理和分布式数据的实际应用:
// lib/models/todo_model.dart
class Todo {
final String id;
final String title;
final bool completed;
final DateTime createdAt;
Todo({
required this.id,
required this.title,
this.completed = false,
required this.createdAt,
});
Todo copyWith({
String? id,
String? title,
bool? completed,
DateTime? createdAt,
}) {
return Todo(
id: id ?? this.id,
title: title ?? this.title,
completed: completed ?? this.completed,
createdAt: createdAt ?? this.createdAt,
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'title': title,
'completed': completed,
'createdAt': createdAt.millisecondsSinceEpoch,
};
}
factory Todo.fromMap(Map<String, dynamic> map) {
return Todo(
id: map['id'],
title: map['title'],
completed: map['completed'],
createdAt: DateTime.fromMillisecondsSinceEpoch(map['createdAt']),
);
}
}
// lib/providers/todo_provider.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:uuid/uuid.dart';
import '../models/todo_model.dart';
import '../services/distributed_kv_service.dart';
final todoListProvider = StateNotifierProvider<TodoListNotifier, List<Todo>>((ref) {
return TodoListNotifier();
});
class TodoListNotifier extends StateNotifier<List<Todo>> {
TodoListNotifier() : super([]) {
_loadFromDistributedStorage();
}
Future<void> _loadFromDistributedStorage() async {
final data = await DistributedKVService.get('todos');
if (data != null) {
final List<dynamic> jsonList = json.decode(data);
final todos = jsonList.map((item) => Todo.fromMap(item)).toList();
state = todos;
}
}
Future<void> _saveToDistributedStorage() async {
final jsonList = state.map((todo) => todo.toMap()).toList();
await DistributedKVService.save('todos', json.encode(jsonList));
}
void addTodo(String title) {
final newTodo = Todo(
id: const Uuid().v4(),
title: title,
createdAt: DateTime.now(),
);
state = [...state, newTodo];
_saveToDistributedStorage();
}
void toggleTodo(String id) {
state = state.map((todo) {
if (todo.id == id) {
return todo.copyWith(completed: !todo.completed);
}
return todo;
}).toList();
_saveToDistributedStorage();
}
void deleteTodo(String id) {
state = state.where((todo) => todo.id != id).toList();
_saveToDistributedStorage();
}
void updateTodo(String id, String newTitle) {
state = state.map((todo) {
if (todo.id == id) {
return todo.copyWith(title: newTitle);
}
return todo;
}).toList();
_saveToDistributedStorage();
}
}
// lib/pages/todo_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../providers/todo_provider.dart';
class TodoPage extends ConsumerWidget {
const TodoPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final todos = ref.watch(todoListProvider);
final notifier = ref.read(todoListProvider.notifier);
return Scaffold(
appBar: AppBar(
title: const Text('待办事项'),
actions: [
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
// 清空已完成
final completedIds = todos
.where((todo) => todo.completed)
.map((todo) => todo.id)
.toList();
for (final id in completedIds) {
notifier.deleteTodo(id);
}
},
),
],
),
body: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
final todo = todos[index];
return ListTile(
leading: Checkbox(
value: todo.completed,
onChanged: (value) => notifier.toggleTodo(todo.id),
),
title: Text(
todo.title,
style: todo.completed
? TextStyle(decoration: TextDecoration.lineThrough)
: null,
),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () => notifier.deleteTodo(todo.id),
),
onTap: () => _editTodo(context, notifier, todo),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _addTodo(context, notifier),
child: const Icon(Icons.add),
),
);
}
void _addTodo(BuildContext context, TodoListNotifier notifier) {
showDialog(
context: context,
builder: (context) {
final controller = TextEditingController();
return AlertDialog(
title: const Text('添加待办'),
content: TextField(
controller: controller,
decoration: const InputDecoration(hintText: '输入待办事项'),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('取消'),
),
TextButton(
onPressed: () {
if (controller.text.isNotEmpty) {
notifier.addTodo(controller.text);
Navigator.pop(context);
}
},
child: const Text('添加'),
),
],
);
},
);
}
void _editTodo(BuildContext context, TodoListNotifier notifier, Todo todo) {
showDialog(
context: context,
builder: (context) {
final controller = TextEditingController(text: todo.title);
return AlertDialog(
title: const Text('编辑待办'),
content: TextField(
controller: controller,
decoration: const InputDecoration(hintText: '输入待办事项'),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('取消'),
),
TextButton(
onPressed: () {
if (controller.text.isNotEmpty) {
notifier.updateTodo(todo.id, controller.text);
Navigator.pop(context);
}
},
child: const Text('保存'),
),
],
);
},
);
}
}
六、总结与关键要点
通过本篇的学习,你应该已经掌握了:
- 状态管理方案选型:Provider、Riverpod等主流方案的特点和适用场景
- 数据持久化技术:SharedPreferences、Hive、SQLite的完整实现
- 鸿蒙分布式数据:分布式键值存储和对象存储的跨设备同步
- 最佳实践:状态分层架构、持久化策略、状态恢复机制
核心价值:通过状态管理和分布式数据同步,你的Flutter应用可以在鸿蒙生态中实现真正的跨设备无缝体验。用户在一台设备上操作的数据,可以实时同步到其他设备,大大提升了应用的使用体验。
下一篇预告 :我们将深入探讨网络请求、API集成与离线缓存,学习如何在Flutter应用中实现高效的网络通信和离线数据管理,让你的应用在网络不稳定的环境下依然能够流畅运行。