Hive هو تخزين NoSQL خفيف الوزن لـ Flutter يعمل بدون كود أصلي. على عكس SQLite أو Firebase، لا يتطلب Hive مكتبات أصلية ويعمل حصرياً عبر Dart. وفقاً لـ Pub.dev، 2024، تم تنزيل Hive أكثر من 10 ملايين مرة ويُستخدم في كل ثالث مشروع Flutter يحتاج إلى تخزين محلي بدون بنية تحتية للخادم.
الوجبات الرئيسية
Hive هي قاعدة بيانات NoSQL مكتوبة بالكامل بلغة Dart ولا تتطلب مكتبات أصلية. تم إنشاؤها بواسطة Simon Leiter في 2019 كبديل لـ SQLite لمشاريع Flutter. يخزن Hive البيانات بتنسيق ثنائي .hive مُحسَّن للقراءة والكتابة السريعة على الأجهزة المحمولة. يستخدم تنسيق .hive مخطط تسلسل مخصص حيث كل نوع بيانات له بادئة بايت خاصة به، مما يسمح بقراءة الملف دون معرفة مسبقة بالمخطط — على عكس Protocol Buffers أو FlatBuffers.
الفكرة الأساسية لـ Hive هي أقصى درجات البساطة. لا تتطلب قاعدة البيانات تهيئة محركات أصلية، ولا تتضمن محلل SQL ولا تستخدم الانعكاس. جميع العمليات هي استدعاءات مباشرة لوظائف Dart مع تسلسل ثنائي عبر WriteBuffer و ReadBuffer.
وفقاً لاستطلاع مجتمع Flutter (2023)، فإن Hive من بين أفضل 5 حزم تخزين بيانات استخداماً في Flutter، ويأتي في المرتبة الثانية بعد shared_preferences من حيث الشعبية، لكنه يتفوق عليه في الوظائف والسرعة.
Hive يستخدم مفهوم Box — وهو مشابه للجدول في قواعد البيانات العلائقية. كل Box هو ملف على القرص يحتوي على مجموعة من أزواج المفتاح-القيمة. يمكن أن يكون المفتاح int أو String، والقيمة يمكن أن تكون أي نوع بدائي أو قائمة أو Map أو كائن مخصص عبر TypeAdapter. الـ Boxes معزولة عن بعضها البعض ويتم فتحها بشكل مستقل.
Hive لا يتطلب قنوات منصة. هذا يعني أنه يعمل بنفس الطريقة على Android و iOS و Web و macOS و Windows و Linux دون إعداد إضافي. للمشاريع التي تستهدف البناء على الويب، يظل Hive الحل الوحيد الخفيف من نوع NoSQL — SQLite لا يعمل في المتصفحات. يستخدم Hive IndexedDB كخلفية للويب، مما يضمن استمرارية البيانات حتى في بيئة المتصفح.
Hive يسلسل البيانات إلى تنسيق ثنائي عند الكتابة ويفك التسلسل عند القراءة. الآلية الداخلية تعتمد على BinaryWriter و BinaryReader، اللذان يحزمان البيانات في مصفوفات بايت مدمجة. حجم التخزين على القرص في المتوسط أصغر 2–3 مرات من تمثيل JSON لنفس البيانات.
عند فتح Box، يقوم Hive بتحميل الملف بأكمله في ذاكرة الوصول العشوائي. هذا يوفر سرعة قراءة عالية (ميكروثانية) لكنه يفرض قيداً على الحجم: يُنصح بتخزين ما لا يزيد عن 50–100 ميغابايت لكل Box. للأحجام الأكبر، استخدم LazyBox — التحميل البطيء للسجلات من القرص.
Hive يعمل في خيط واحد داخل معزل Dart. عمليات الكتابة تتم بشكل متزامن مع قفل الملف. للوصول غير المتزامن، استخدم Hive.openBox() مع await. الوصول المتزامن من معازل متعددة غير مدعوم مباشرة — يتطلب آلية مزامنة منفصلة.
Hive يحتل مكانة بين SharedPreferences و SQLite. هو أكثر تعقيداً من SharedPreferences (يدعم الكائنات المخصصة) لكنه أبسط من SQLite (لا يتطلب استعلامات SQL). دعنا نقارن الخصائص الرئيسية.
| الخاصية | Hive | SharedPreferences | SQLite |
|---|---|---|---|
| أنواع البيانات | أي (عبر TypeAdapter) | بدائية فقط | أنواع SQL |
| سرعة القراءة | ~30,000 ops/s | ~5,000 ops/s | ~2,000 ops/s |
| الكود الأصلي | غير مطلوب | مطلوب (Android) | مطلوب |
| دعم الويب | نعم | لا | لا |
| التعقيد | منخفض | أدنى | متوسط |
| التفاعلية | WatchBox | لا | عبر ORM |
Hive مثالي لأحجام البيانات الصغيرة: إعدادات التطبيق، ذاكرة تخزين مؤقت لاستجابات API، قائمة مزامنة محلية، المفضلة وسجل التصفح. إذا كانت البيانات لا تتجاوز 50 MB ولا تتطلب استعلامات علائقية — فإن Hive أسرع وأبسط من SQLite.
Hive لا يدعم الاستعلامات مع تصفية حسب عدة حقول، أو JOIN، أو دوال التجميع. إذا كنت بحاجة إلى استعلامات معقدة مثل «تحديد جميع المهام لليوم ذات الأولوية فوق 3» — استخدم SQLite مع drift أو floor. Hive أيضاً غير مناسب لتخزين أكثر من 100 MB من البيانات بسبب التحميل في الذاكرة.
Hive يبدأ بالتهيئة وفتح Box. فيما يلي العمليات الأساسية لسيناريو نموذجي — تخزين قائمة مهام في تطبيق Flutter. جميع الأمثلة تعمل دون استدعاءات منصة أصلية.
قبل استخدام Hive، يجب استدعاء Hive.initFlutter() في الدالة main. ثم افتح Box عبر Hive.openBox() — ستكون النتيجة كائن Box جاهز للقراءة والكتابة.
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
void async main() {
await Hive.initFlutter();
final settingsBox = await Hive.openBox('settings');
runApp(MyApp());
}
Box يوفر دوال put, get, delete ومكرراً لاجتياز جميع الإدخالات. يتم كتابة المفاتيح والقيم عبر الأدوية — بشكل افتراضي Box<dynamic> يقبل أي نوع، لكن يُنصح بتحديد نوع محدد.
// كتابة البيانات
final box = await Hive.openBox<String>('tasks');
await box.put('task_1', 'شراء بقالة');
// قراءة
final task = box.get('task_1');
// جميع المفاتيح
final allTasks = box.values.toList();
// حذف
await box.delete('task_1');
// مسح Box
await box.clear();
WatchBox هو امتداد لـ Box يقوم بإعلام المشتركين بالتغييرات. في Flutter، يتكامل هذا مع ValueListenableBuilder: عندما تتغير أي قيمة في Box، يتم إعادة بناء القطعة تلقائياً دون استدعاء setState.
final watchBox = await Hive.openBox('settings');
// في القطعة
ValueListenableBuilder(
valueListenable: watchBox.listenable(),
builder: (context, box, _) {
final counter = box.get('counter') ?? 0;
return Text('العداد: $counter');
},
)
TypeAdapter هي آلية Hive لتسلسل كائنات Dart المخصصة. يصف المحول كيفية تحويل كائن إلى تنسيق ثنائي (write) والعكس (read). على عكس json_serializable، لا يتطلب TypeAdapter انعكاساً وهو أسرع.
المحول يطبق واجهة TypeAdapter
// نموذج البيانات
class Task {
final String title;
final bool isCompleted;
Task({required this.title, this.isCompleted = false});
}
// TypeAdapter
class TaskAdapter extends TypeAdapter<Task> {
@override
final int typeId = 0;
@override
Task read(BinaryReader reader) {
return Task(
title: reader.readString(),
isCompleted: reader.readBool(),
);
}
@override
void write(BinaryWriter writer, Task obj) {
writer.writeString(obj.title);
writer.writeBool(obj.isCompleted);
}
}
للمشاريع التي تحتوي على عدد كبير من النماذج، يوفر Hive hive_generator و build_runner. التعليمة @HiveType على الفئة و @HiveField على الحقول تولد المحول تلقائياً. هذا مناسب عندما يحتوي النموذج على 10+ حقول — الكتابة اليدوية لـ read/write تصبح مملة.
Hive يقرأ من الذاكرة بدلاً من القرص، مما يوفر سرعات تصل إلى 30,000 عملية في الثانية. للتحسين: افتح Box مرة واحدة وأعد استخدامه في جميع أنحاء التطبيق، لا تستدع openBox بشكل متكرر. استخدم Hive.box() (محصل متزامن) بعد التهيئة — يعيد Box مفتوحاً بالفعل دون إنشاء مثيل جديد.
Hive يتكامل بسهولة مع مديري الحالة المشهورين في Flutter. لـ Provider، استخدم ChangeNotifierProvider الذي يقرأ البيانات من Box عند التهيئة ويتم تحديثه عبر listenable. لـ Riverpod، StreamProvider مشترك في WatchBox يعمل بشكل جيد. هذا المزيج يوفر تحديثات تفاعلية لواجهة المستخدم عند كل تغيير في بيانات Hive دون استدعاءات يدوية لـ setState. في مشروع Flutter نموذجي، تسمح هذه البنية بمزامنة الحالة بين الشاشات دون مفردة عالمية.
الأسئلة الشائعة
Hive يعمل على Dart النقي، لذلك يمكن استخدامه في أي مشروع Dart: خادم (Dart VM)، تطبيق وحدة تحكم أو AngularDart. لـ Flutter، يلزم بالإضافة إلى ذلك hive_flutter لتهيئة مسارات التخزين.
Hive يدعم تشفير AES-256 من خلال معامل encryptionKey عند فتح Box. يجب أن يكون المفتاح سلسلة من 32 بايت. لا يمكن قراءة Box المشفر بدون المفتاح — البيانات محمية على مستوى الملف.
Isar هو خليفة Hive من نفس المؤلف (Simon Leiter). Isar أسرع، ويدعم الفهارس والعلاقات والاستعلامات المعقدة. ومع ذلك، يظل Hive مناسباً للسيناريوهات البسيطة حيث لا تكون هناك حاجة للإمكانيات العلائقية لـ Isar، وللمشاريع حيث تكون التبعيات البسيطة مهمة.
Hive لا يحتوي على ترحيل مدمج. إذا تغير هيكل TypeAdapter، فلن يتم فك تسلسل البيانات القديمة. الحل: قم بزيادة typeId للمحول وكتابة ترحيل يدوي في الكود، أو استخدم delete للمفتاح القديم قبل كتابة مفتاح جديد.
Hive يقوم بتحميل Box بالكامل في الذاكرة. الحد الموصى به هو 50–100 ميغابايت لكل Box. قد يؤدي تجاوز هذا إلى تأخيرات عند فتح Box وزيادة استهلاك RAM. للأحجام الأكبر، استخدم عدة Boxes أو LazyBox مع التحميل البطيء.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا