ورود و عضویت
0
سبد خرید شما خالی است
0
سبد خرید شما خالی است

ذخیره کردن اطلاعات در فلاتر با دیتابیس Hive

6 دیدگاه
10 دقیقه برای مطالعه

راه های مختلفی برای ذخیره سازی اطلاعات در یک اپلیکیشن وجود دارد که در مطالب قبلی با آنها نیز آشنا شده ایم مثل استفاده از دیتابیس SQLite و یا ذخیره سازی به وسیله SharedPreferences اما در این مطلب ابزار جدیدی به اسم Hive این کار انجام خواهیم داد.

Hive یک دیتابیس سبک, سریع و از نوع NoSQL در زبان دارت و فلاتر می باشد.

در این مقاله انجام عملیات CRUD را با استفاده از این پکیج قرار است انجام دهیم.

آماده سازی پروژه

در این پروژه از Provider استفاده میکنیم که اگر با آن آشنا نیستید بهتر است اول درباره آن مطالعه کنید تا به مشکل نخورید همچنین با طراحی رابط کاربری نیز باید آشنا باشید.

برای اینکه سرعت بیشتری در کار داشته باشیم پروژه ابتدایی آموزش را از انتهای صفحه دانلود کنید. در این پروژه بخش Provider و رابط کاربری ایجاد شده است و مانند تصویر زیر در اختیار شماست.

آموزش Hive

بعد از دانلود کردن پروژه نیاز به اضافه کردن پکیج های مختلفی داریم که در بخش زیر میتونید مشاهده کنید.

hive: ^1.4.1+1
provider: ^4.3.1
path_provider: ^1.6.5
hive_generator: ^0.5.0

پکیج hive_generator را در بخش dev dependencies قرار دهید.

پیاده سازی Hive

قبل از اینکه از hive استفاده کنید باید در بخش main آن را تنظیم کنید.

import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart' as pathProvider;

Future<void> main() async {
  Directory directory = await pathProvider.getApplicationDocumentsDirectory();
  Hive.init(directory.path);

  runApp(MyApp());
}

با این کار مسیر ذخیره سازی اطلاعات را مشخص میکنیم.

Hive Boxes

زمانی که با Hive کار میکنید اطلاعات به شکل جدول و ستون ذخیره نمیشوند چون گفتیم که دیتابیس ما از نوع No SQL است.

در اینجا مفهومی داریم به نام Box که اطلاعات درون این Box یا جعبه ها ذخیره می شوند.

این جعبه را میتونید مانند یک پوشه در کامپیوتر تصور کنید.

قبل از اینکه بتونید اطلاعات را بخوانید یا بنویسید باید ابتدا این Box را باز کنید که این کار با دستور await Hive.openBox(‘name’) قابل انجام است.

برای دسترسی به نمونه ای از جعبه ای که قبلا باز شده است هم میتونید از دستور Hive.box(‘name’) استفاده کنید.

معرفی TypeAdapters

در این نوع دیتابیس امکان ذخیره سازی انواع داده های معمول مثل String, int, Map, List, DateTime را دارید.

اما ممکن است بخواهید یک کلاس مدل از داده های خود داشته باشید و سریعتر اطلاعات را ذخیره و بازیابی کنید. در این حالت باید از TypeAdapters استفاده کنید که کار دیکد و انکد کردن اشیای کلاس را انجام میدهد.

در مسیری که مایل هستید یک فایل جدید برای کلاس مدل ایجاد کنید, در اینجا اسم فایل را inventory_model قرار داده ایم.

در این فایل کلاس خودمون و با استفاده از annotations های مخصوص TypeAdapters  ایجاد میکنیم تا فایل های متناسب با کلاس ما به شکل خودکار ساخته شود.

import 'package:hive/hive.dart';

part 'inventory_model.g.dart';

@HiveType()
class Inventory {
  @HiveField(0)
  final String name;

  @HiveField(1)
  final String description;

  Inventory({this.name, this.description});
}

برای اینکه از کلاس خودتون بتونید در دیتابیس استفاده کنید باید قبل از اسم کلاس از برچسب یا انوتیشن @HiveType() استفاده کنید.

سپس هر فیلد از کلاس را که قصد دارید داخل دیتابیس قرار بگیرد با انوتیشن @HiveField(index) مشخص میکنید و یک ایندکس که عددی صحیح و منحصر به فرد است را برای آن قرار میدهید.

حالا برای ساخته شدن ابزارهای موردنیاز دستور زیر را در ترمینال وارد کنید.

$ flutter packages pub run build_runner build

در این قسمت شاید با خطایی مثل Missing concrete implementation of ‘getter TypeAdapter.typeId’ روبرو شوید.

برای حل این مشکل کافیست یک متد get برای فیلد typeId  بنویسید.

@override
int get typeId => 0;

بعد از رفع خطا زمان رجیستر کردن اداپتر در متد main فرا رسیده.

Hive.registerAdapter(InventoryAdapter());
runApp(MyApp());

ذخیره اطلاعات

برای ذخیره کردن اطلاعات یک متد برای اینکار در کلاس ChangeNotifier مینویسیم.

addItem(Inventory item) async {
    var box = await Hive.openBox<Inventory>('inventory');

    box.add(item);

    notifyListeners();
  }

در اینجا ابتدا همانطور که قبل تر گفتیم ابتدا یک box  را باز میکنیم و سپس از متد add استفاده میکنیم تا اطلاعات را به آن اضافه کنیم.

برای اینکار میتونید از متد put() هم استفاده کنید اما تفاوت این روش با متد قبلی استفاده از یک کلید برای ذخیره سازی است.

box.put(‘key’, item) در حالی که متد add فقط یک ایندکس به شکل خودکار برای هر سری از اطلاعات در نظر میگیرد.

برای ذخیره سازی همچنین میتونید از متد box.putAll({‘key’: value}) نیز استفاده کنید که یک مپ را به عنوان ورودی دریافت میکند و یا متد box.addAll( ) که پارامتر ورودی آن لیست است.

برای استفاده عملی از کد زیر میتوانید استفاده کنید.

inputItemDialog(BuildContext context, String action, [int index]) {
    var inventoryDb = Provider.of<HomeModel>(context, listen: false);

    showDialog(
      context: context,
      builder: (context) {
        return Dialog(
          child: Container(
            padding: EdgeInsets.only(
              left: 15,
              right: 15,
              top: 40,
            ),
            height: 45.height,
            child: SingleChildScrollView(
              child: Form(
                key: _formKey,
                child: Column(
                  children: <Widget>[
                    Text(
                      action == 'add' ? 'Add Item' : 'Update Item',
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 20,
                      ),
                    ),
                    SizedBox(
                      height: 10,
                    ),
                    TextFormField(
                      controller: nameController,
                      validator: (value) {
                        if (value.isEmpty) {
                          return 'Item name cannot be empty';
                        }
                        return null;
                      },
                      decoration: InputDecoration(
                        labelText: 'Item name',
                      ),
                    ),
                    SizedBox(
                      height: 40,
                    ),
                    TextFormField(
                      controller: descriptionController,
                      validator: (value) {
                        if (value.isEmpty) {
                          return 'Item description cannot be empty';
                        }
                        return null;
                      },
                      decoration: InputDecoration(
                        labelText: 'Item description',
                      ),
                    ),
                    SizedBox(
                      height: 40,
                    ),
                    RaisedButton(
                      onPressed: () async {
                        if (_formKey.currentState.validate()) {
                          if (action == 'add') {
                            await inventoryDb.addItem(Inventory(
                              name: nameController.text,
                              description: descriptionController.text,
                            ));
                          } else {
                            
                          }

                          nameController.clear();
                          descriptionController.clear();

                          inventoryDb.getInventory();

                          Navigator.pop(context);
                        }
                      },
                      color: Colors.green[600],
                      child: Text(
                        action == 'add' ? 'Add' : 'update',
                        style: TextStyle(
                          fontSize: 16,
                          color: Colors.white,
                        ),
                      ),
                    ),
                    SizedBox(
                      height: 20,
                    )
                  ],
                ),
              ),
            ),
          ),
        );
      },
    );
  }

خواندن اطلاعات

سه روش مختلف برای خواندن اطلاعات ذخیره شده وجود دارد.

  • box.get(‘key): دریافت اطلاعات مربوط به یک کلید
  • box.getAt(index): دریافت اطلاعات مربوط به یک ایندکس
  • box.values: شامل تمام اطلاعات موجود در باکس

متد جدیدی به کلاسمون اضافه میکنیم برای خواندن اطلاعات به شکل زیر:

List _inventoryList = <Inventory>[];
List get inventoryList => _inventoryList;

getItem() async {
    final box = await Hive.openBox<Inventory>('inventory');

    _inventoryList = box.values.toList();

    notifyListeners();
 }

برای استفاده از این متد در رابط کاربری پروژمون کد زیر را در بالای متد build قرار دهید.

context.watch<HomeModel>().getItem();
ListView.builder(
     itemCount: model.inventoryList.length,
     itemBuilder: (context, index) {
       Inventory inv = model.inventoryList[index];
       return Container(
          margin: EdgeInsets.symmetric(
          vertical: 2.height,
          horizontal: 4.5.width,
         ),
          height: 13.height,
          decoration: BoxDecoration(
          color: Colors.white,
          ),
          child: Row(
            children: <Widget>[
              Container(
                margin: EdgeInsets.only(left: 2.width),
                width: 16.width,
                decoration: BoxDecoration(
                color: Colors.green[600],
                shape: BoxShape.circle,
                ),
                child: Center(
                  child: Icon(
                     Icons.home,
                     color: Colors.white,
                        ),
                      ),
                    ),
                    Padding(
                     padding: EdgeInsets.symmetric(
                     vertical: 3.height,
                     horizontal: 3.width,
                     ),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                         children: <Widget>[
                            Text(
                             inv.name,
                              style: TextStyle(
                               color: Colors.green[600],
                               fontWeight: FontWeight.w600,
                               fontSize: 4.5.text,
                                 ),
                               ),
                               SizedBox(
                                height: 1.height,
                               ),
                                  Text(
                                    inv.description,
                                    style: TextStyle(
                                      color: Colors.grey,
                                      fontSize: 4.text,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            Padding(
                              padding: EdgeInsets.only(left: 8.width),
                              child: PopupMenuButton(
                                onSelected: (item) {
                                  switch (item) {
                                    case 'update':
                                      nameController.text = inv.name;
                                      descriptionController.text =
                                          inv.description;

                                      inputItemDialog(context, 'update', index);
                                      break;
                                    case 'delete':
                                      model.deleteAt(index);
                                  }
                                },
                                itemBuilder: (context) {
                                  return [
                                    PopupMenuItem(
                                      value: 'update',
                                      child: Text('Update'),
                                    ),
                                    PopupMenuItem(
                                      value: 'delete',
                                      child: Text('Delete'),
                                    ),
                                  ];
                                },
                              ),
                            ),
                          ],
                        ),
                      );
                    },
                  )

آپدیت اطلاعات

در لیستی که داریم که با کلیک روی هر آیتم منوی پاپ آپی باز میشود که گزینه آپدیت دارد.

برای بروزرسانی مقادیر ذخیره شده از دو متد زیر میتونید کمک بگیرید.

  • box.put(‘key’, newValue)
  • box.putAt(index, item)

مثل دفعات قبلی متد مخصوص این کار را نیز به کلاس اضافه میکنیم.

updateItem(int index, Inventory inventory) {
    final box = Hive.box<Inventory>('inventory');

    box.putAt(index, inventory);

    notifyListeners();
  }

حذف آیتم

پاک کردن اطلاعات در Hive تقریبا مثل اضافه کردن اطلاعات می باشد.

  • box.delete(‘key)
  • box.deleteAt(index)
  • box.add()
  • box.deleteAll(keys)

همچنین یک متد deleteFromDisk هم وجود دارد که فایل box را پاک میکند.

deleteItem(int index) {
    final box = Hive.box<Inventory>(_inventoryBox);

    box.deleteAt(index);

    getInventory();

    notifyListeners();
  }

Lazy Boxes

اگر در پروژه موبایل خود نیاز به ذخیره حجم زیاد اطلاعات در دیتابیس دارید بهتر است که از lazyBox ها استفاده کنید. در این نوع از ذخیره سازی تمام اطلاعات همزمان از روی دیسک خوانده نمیشود.

final lazyBox = await Hive.openLazyBox('name');

var value = await lazyBox.get('key');

مابقی موارد در این نوع ذخیره سازی مشابه موارد گفته شده می باشد.

6 پاسخ به “ذخیره کردن اطلاعات در فلاتر با دیتابیس Hive”

  1. Ali4yo گفت:

    چه تفاوت هایی از نظر عملکردی با SQlite داره

  2. ooo گفت:

    لطفاً این رو هم اضافه بفرمایید که nosql هست و قابلیت کوئری‌های پیچیده زدن رو نداره. برای داده‌های جدولی و ساختارمند مناسب نیست.

  3. sam گفت:

    فایل خراب بود 😐

  4. رضا گفت:

    قابلیت join زدن چند جدول(باکس) و اعمال شرط ، در این روش هست ؟

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

Hesam
11 آوریل 2021
آموزش فارسی فلاتر
آموزش فارسی flutter