Hive — یک ذخیرهساز سبک NoSQL برای Flutter است که بدون کد بومی کار میکند. برخلاف SQLite یا Firebase، Hive نیاز به اتصال کتابخانههای بومی ندارد و منحصراً از طریق Dart کار میکند. بر اساس Pub.dev، 2024، Hive بیش از 10 میلیون بار دانلود شده و در هر سومین پروژه Flutter که نیاز به ذخیرهسازی محلی داده بدون زیرساخت سرور دارد، استفاده میشود.
نکات اصلی
Hive — یک پایگاه داده NoSQL است که کاملاً در Dart نوشته شده و به کتابخانههای بومی نیاز ندارد. توسط Simon Leiter در سال ۲۰۱۹ به عنوان جایگزینی برای SQLite در پروژههای Flutter ایجاد شد. Hive دادهها را در قالب باینری .hive ذخیره میکند که برای خواندن و نوشتن سریع در دستگاههای موبایل بهینه شده است. فرمت .hive از یک طرح سریالسازی سفارشی استفاده میکند که در آن هر نوع داده پیشوند بایت مخصوص خود را دارد و این امکان را میدهد که فایل بدون دانش قبلی از طرح خوانده شود — برخلاف Protocol Buffers یا FlatBuffers.
ایده اصلی Hive — حداکثر سادگی است. پایگاه داده به راهاندازی موتورهای بومی نیاز ندارد، شامل تجزیهگر SQL نیست و از بازتاب (reflection) استفاده نمیکند. همه عملیاتها فراخوانی مستقیم توابع Dart با سریالسازی باینری از طریق WriteBuffer و ReadBuffer هستند.
بر اساس نظرسنجی Flutter Community (۲۰۲۳)، Hive در بین ۵ بسته پرکاربرد برای ذخیرهسازی داده در Flutter قرار دارد و از نظر محبوبیت فقط پس از shared_preferences است، اما از نظر عملکرد و سرعت از آن پیشی میگیرد.
Hive از مفهوم Box استفاده میکند — مشابه جدول در پایگاههای داده رابطهای. هر Box یک فایل روی دیسک با مجموعهای از جفتهای کلید-مقدار است. کلید میتواند int یا String باشد، مقدار — هر نوع اولیه، لیست، Map یا شیء سفارشی از طریق TypeAdapter. Boxها از یکدیگر ایزوله هستند و به طور مستقل باز میشوند.
Hive به کانالهای پلتفرمی (platform channels) نیاز ندارد. این بدان معناست که روی Android، iOS، Web، macOS، Windows و Linux بدون پیکربندی اضافی یکسان کار میکند. برای پروژههایی که هدف آنها کامپایل وب است، Hive تنها راهحل سبک NoSQL باقی میماند — SQLite در مرورگر کار نمیکند. در عین حال Hive از IndexedDB به عنوان بکاند برای وب استفاده میکند که ماندگاری دادهها را در محیط مرورگر تضمین میکند.
Hive دادهها را در زمان نوشتن به فرمت باینری سریالایز و در زمان خواندن دیسریالایز میکند. مکانیزم داخلی بر اساس BinaryWriter و BinaryReader است که دادهها را در آرایههای بایت فشرده بستهبندی میکنند. اندازه ذخیرهساز روی دیسک به طور متوسط ۲ تا ۳ برابر کوچکتر از نمایش JSON همان دادهها است.
هنگام باز کردن Box، Hive کل فایل را در حافظه RAM بارگذاری میکند. این سرعت بالای خواندن (میکروثانیه) را تضمین میکند، اما محدودیتی بر اندازه داده اعمال میکند: توصیه میشود بیش از ۵۰-۱۰۰ مگابایت در یک Box ذخیره نکنید. برای حجمهای بزرگتر از LazyBox — بارگذاری تنبل رکوردها از دیسک استفاده کنید.
Hive به صورت تکرشتهای در ایزوله Dart کار میکند. عملیات نوشتن به صورت همزمان با قفل فایل انجام میشود. برای دسترسی ناهمزمان از Hive.openBox() با await استفاده کنید. دسترسی همروند از چندین ایزوله به طور مستقیم پشتیبانی نمیشود — برای این کار به یک مکانیزم همگامسازی جداگانه نیاز است.
Hive جایگاهی بین SharedPreferences و SQLite دارد. از SharedPreferences پیچیدهتر است (اشیاء سفارشی را پشتیبانی میکند)، اما از SQLite سادهتر است (نیاز به کوئریهای SQL ندارد). ویژگیهای کلیدی را مقایسه کنیم.
| ویژگی | Hive | SharedPreferences | SQLite |
|---|---|---|---|
| انواع داده | هر نوع (از طریق TypeAdapter) | فقط اولیهها | انواع SQL |
| سرعت خواندن | ~۳۰٬۰۰۰ ops/s | ~۵٬۰۰۰ ops/s | ~۲٬۰۰۰ ops/s |
| کد بومی | نیاز ندارد | نیاز دارد (Android) | نیاز دارد |
| پشتیبانی وب | بله | خیر | خیر |
| پیچیدگی | کم | حداقل | متوسط |
| واکنشگرایی | WatchBox | خیر | از طریق ORM |
Hive برای حجمهای کوچک داده بهینه است: تنظیمات برنامه، کش پاسخهای API، صف همگامسازی محلی، موارد علاقهمندی و تاریخچه بازدید. اگر دادهها از ۵۰ مگابایت تجاوز نمیکنند و به کوئریهای رابطهای نیاز ندارند — Hive سریعتر و سادهتر از SQLite است.
Hive از کوئریهای با فیلتر بر چندین فیلد، JOIN، توابع تجمعی پشتیبانی نمیکند. اگر به کوئریهای پیچیده مانند «انتخاب همه وظایف امروز با اولویت بالای ۳» نیاز دارید — از SQLite با drift یا floor استفاده کنید. Hive همچنین برای ذخیره بیش از ۱۰۰ مگابایت داده به دلیل بارگذاری در حافظه مناسب نیست.
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 به بازتاب (reflection) نیاز ندارد و سریعتر کار میکند.
آداپتور اینترفیس 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 روی فیلدها آداپتور را به طور خودکار تولید میکند. این زمانی مفید است که مدل شامل ۱۰+ فیلد باشد — نوشتن دستی read/write وقتگیر میشود.
Hive خواندن را از حافظه انجام میدهد، نه از دیسک، که سرعت تا ۳۰٬۰۰۰ عملیات در ثانیه را فراهم میکند. برای بهینهسازی: Box را یک بار باز کنید و در کل برنامه از آن مجدداً استفاده کنید، openBox را دوباره فراخوانی نکنید. پس از راهاندازی از Hive.box() (getter همزمان) استفاده کنید — بدون ایجاد نمونه جدید، Box از قبل باز شده را برمیگرداند.
Hive به راحتی با مدیریتکنندههای حالت محبوب Flutter یکپارچه میشود. برای Provider از ChangeNotifierProvider استفاده کنید که دادهها را از Box در زمان راهاندازی میخواند و از طریق listenable بهروز میشود. برای Riverpod StreamProvider که روی WatchBox مشترک میشود مناسب است. چنین ترکیبی بهروزرسانی واکنشگرای UI را در هر تغییر داده در Hive بدون فراخوانی دستی setState فراهم میکند. در یک پروژه معمولی Flutter چنین معماری به همگامسازی وضعیت بین صفحهها بدون singleton سراسری اجازه میدهد.
سوالات متداول
Hive در Dart خالص کار میکند، بنابراین میتوان از آن در هر پروژه Dart استفاده کرد: سروری (Dart VM)، کنسولی یا AngularDart. برای Flutter علاوه بر این hive_flutter با راهاندازی مسیرهای ذخیرهسازی متصل میشود.
Hive از رمزگذاری AES-256 از طریق پارامتر encryptionKey هنگام باز کردن Box پشتیبانی میکند. کلید باید یک رشته ۳۲ بایتی باشد. Box رمزگذاری شده بدون کلید قابل خواندن نیست — دادهها در سطح فایل محافظت میشوند.
Isar — جانشین Hive از همان نویسنده (Simon Leiter). Isar سریعتر است، از ایندکسها، روابط و کوئریهای پیچیده پشتیبانی میکند. با این حال Hive برای سناریوهای ساده که نیازی به قابلیتهای رابطهای Isar نیست و برای پروژههایی که وابستگی حداقلی مهم است، همچنان مرتبط باقی میماند.
Hive مهاجرت داخلی ندارد. اگر ساختار TypeAdapter تغییر کند، دادههای قدیمی دیسریالایز نخواهند شد. راهحل: typeId آداپتور را افزایش دهید و مهاجرت دستی در کد بنویسید یا قبل از نوشتن کلید جدید از delete برای کلید قدیمی استفاده کنید.
Hive Box را به طور کامل در حافظه بارگذاری میکند. حد توصیه شده ۵۰-۱۰۰ مگابایت برای یک Box است. در صورت تجاوز، تأخیر در باز کردن Box و افزایش مصرف RAM ممکن است. برای حجمهای بزرگتر از چند Box یا LazyBox با بارگذاری تنبل استفاده کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید