إدارة الحالة (State Management) من أهم التحديات في تطوير تطبيقات Flutter، خصوصًا عند الحاجة إلى الاحتفاظ ببيانات التطبيق بعد إغلاقه. هنا يأتي دور HydratedBloc كحل عملي وفعال يتيح حفظ الحالة تلقائيًا واستعادتها عند إعادة تشغيل التطبيق، مما يوفر تجربة مستخدم أكثر سلاسة واستقرارًا.
لماذا نستخدم HydratedBloc لحفظ الحالة في Flutter؟
في التطبيقات الحقيقية، يحتاج المستخدم إلى استكمال ما بدأه دون فقدان البيانات. بدلًا من إعادة تحميل الحالة أو استخدام حلول يدوية مثل SharedPreferences، يوفر HydratedBloc آلية ذكية لحفظ الحالة واسترجاعها تلقائيًا دون تعقيد.
ما هو HydratedBloc؟
HydratedBloc هو امتداد لمكتبة Bloc يضيف ميزة التخزين المحلي التلقائي للحالة. يعتمد على مكتبة hydrated_bloc التي تقوم بتخزين الحالة بصيغة JSON في التخزين المحلي باستخدام Hive أو SharedPreferences.
عند إعادة تشغيل التطبيق، يتم استعادة آخر حالة محفوظة تلقائيًا دون أي تدخل من المطور.
عندما يتم إغلاق التطبيق أو إعادة تشغيله، يتم حفظ الحالة الحالية في التخزين المحلي، ويمكن استعادتها عند تشغيل التطبيق مرة أخرى. هذا يجعل HydratedCubit أداة مثالية للتطبيقات التي تحتاج إلى الحفاظ على بيانات المستخدم أو حالة التطبيق بين الجلسات.
كيفية تثبيت hydrated_bloc في مشروع Flutter
أضف الاعتمادات التالية إلى ملف pubspec.yaml:
dependencies:
flutter:
sdk: flutter
hydrated_bloc: ^8.0.0
path_provider: ^2.0.11
تهيئة HydratedBloc عند تشغيل التطبيق
قبل استخدام HydratedCubit أو HydratedBloc، يجب تهيئة التخزين في نقطة بدء التطبيق:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
HydratedBloc.storage = await HydratedStorage.build(
storageDirectory: await getTemporaryDirectory(),
);
runApp(const MyApp());
}
استخدام HydratedCubit مع Cubit
class CounterCubit extends HydratedCubit {
CounterCubit() : super(const CounterInit());
void increment() {
emit(CounterUpdate(state.count + 1));
}
void decrement() {
emit(CounterUpdate(state.count - 1));
}
@override
CounterState? fromJson(Map json) {
return CounterUpdate(json['count']);
}
@override
Map? toJson(CounterState state) {
return {'count': state.count};
}
}
في هذا المثال:
- يتم حفظ قيمة العداد تلقائيًا
- fromJson تُستخدم لاستعادة الحالة
- toJson تُستخدم لحفظ الحالة في التخزين المحلي
استخدام HydratedBloc مع Bloc
class TaskBloc extends HydratedBloc {
TaskBloc() : super(TaskInitial()) {
on(_addTask);
on(_removeTask);
on(_toggleTask);
}
void _addTask(AddTaskEvent event, Emitter emit) {
final task = TaskModel(
id: const Uuid().v4(),
title: event.title,
isCompleted: false,
);
emit(UpdateTask([...state.tasksList, task]));
}
void _removeTask(RemoveTaskEvent event, Emitter emit) {
emit(UpdateTask(
state.tasksList.where((t) => t.id != event.id).toList(),
));
}
void _toggleTask(ToggleTaskEvent event, Emitter emit) {
emit(UpdateTask(
state.tasksList.map((task) {
return task.id == event.id
? task.copyWith(isCompleted: !task.isCompleted)
: task;
}).toList(),
));
}
@override
TaskState? fromJson(Map json) {
return UpdateTask(
(json['tasks'] as List)
.map((e) => TaskModel.fromJson(e))
.toList(),
);
}
@override
Map? toJson(TaskState state) {
return {
'tasks': state.tasksList.map((e) => e.toJson()).toList(),
};
}
}
تعريف حالة المهام (State)
abstract class TaskState {
final List tasksList;
TaskState(this.tasksList);
}
class TaskInitial extends TaskState {
TaskInitial() : super([]);
}
class UpdateTask extends TaskState {
UpdateTask(List tasksList) : super(tasksList);
}
متى لا يكون HydratedBloc هو الخيار المناسب؟
- عند التعامل مع بيانات حساسة (مثل كلمات المرور)
- عند الحاجة إلى تخزين مؤقت فقط
- في الحالات التي تتطلب مزامنة فورية مع السيرفر
مزايا استخدام HydratedBloc في Flutter
- حفظ واستعادة الحالة تلقائيًا
- تقليل الكود المتكرر
- تحسين تجربة المستخدم
- تكامل مثالي مع Bloc
أسئلة شائعة حول HydratedBloc
هل HydratedBloc يؤثر على أداء التطبيق؟
لا، يتم التخزين بطريقة غير متزامنة ولا يؤثر بشكل ملحوظ على الأداء.
هل يمكن استخدام HydratedBloc مع Riverpod؟
لا، HydratedBloc مصمم خصيصًا للعمل مع Bloc و Cubit.


