فعال کردن قابلیت های آفلاین

برنامه های Firebase حتی اگر برنامه شما به طور موقت اتصال شبکه خود را قطع کند، کار می کنند. علاوه بر این، Firebase ابزارهایی را برای تداوم داده ها به صورت محلی، مدیریت حضور و مدیریت تأخیر فراهم می کند.

پایداری دیسک

برنامه های Firebase به طور خودکار وقفه های موقت شبکه را کنترل می کنند. داده‌های ذخیره‌شده در حافظه پنهان در حالت آفلاین در دسترس هستند و Firebase هنگام بازیابی اتصال شبکه، هر نوشته‌ای را دوباره ارسال می‌کند.

وقتی پایداری دیسک را فعال می‌کنید، برنامه شما داده‌ها را به صورت محلی در دستگاه می‌نویسد تا برنامه شما بتواند در حالت آفلاین وضعیت را حفظ کند، حتی اگر کاربر یا سیستم عامل برنامه را مجدداً راه‌اندازی کند.

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

FirebaseDatabase.instance.setPersistenceEnabled(true);

رفتار پایدار

با فعال کردن تداوم، هر داده‌ای که مشتری پایگاه داده بیدرنگ Firebase در حالت آنلاین همگام‌سازی می‌کند، روی دیسک باقی می‌ماند و به صورت آفلاین در دسترس است، حتی زمانی که کاربر یا سیستم عامل برنامه را مجدداً راه‌اندازی می‌کند. این بدان معنی است که برنامه شما با استفاده از داده های محلی ذخیره شده در حافظه پنهان، همانطور که بصورت آنلاین انجام می شود کار می کند. تماس‌های شنونده برای به‌روزرسانی‌های محلی فعال می‌شوند.

سرویس گیرنده پایگاه داده بیدرنگ Firebase به طور خودکار یک صف از تمام عملیات نوشتن که در زمانی که برنامه شما آفلاین است انجام می شود نگه می دارد. هنگامی که تداوم فعال است، این صف نیز روی دیسک باقی می ماند تا زمانی که کاربر یا سیستم عامل برنامه را مجددا راه اندازی می کند، همه نوشته های شما در دسترس باشد. هنگامی که برنامه اتصال مجدد را به دست آورد، همه عملیات به سرور پایگاه داده بیدرنگ Firebase ارسال می شود.

اگر برنامه شما از احراز هویت Firebase استفاده می‌کند، سرویس گیرنده پایگاه داده بیدرنگ Firebase، رمز احراز هویت کاربر را در طول راه‌اندازی مجدد برنامه ادامه می‌دهد. اگر رمز تأیید اعتبار زمانی که برنامه شما آفلاین است منقضی شود، مشتری عملیات نوشتن را متوقف می کند تا زمانی که برنامه شما مجدداً کاربر را تأیید کند، در غیر این صورت ممکن است عملیات نوشتن به دلیل قوانین امنیتی با شکست مواجه شود.

تازه نگه داشتن داده ها

پایگاه داده بیدرنگ Firebase یک کپی محلی از داده ها را برای شنوندگان فعال همگام و ذخیره می کند. علاوه بر این، می توانید مکان های خاص را همگام نگه دارید.

final scoresRef = FirebaseDatabase.instance.ref("scores");
scoresRef.keepSynced(true);

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

scoresRef.keepSynced(false);

به طور پیش‌فرض، 10 مگابایت از داده‌های همگام‌سازی شده قبلی در حافظه پنهان ذخیره می‌شود. این باید برای اکثر برنامه ها کافی باشد. اگر حافظه پنهان از اندازه پیکربندی شده خود بیشتر شود، پایگاه داده بیدرنگ Firebase داده هایی را که اخیراً کمتر استفاده شده اند را پاک می کند. داده هایی که همگام نگه داشته می شوند از حافظه پنهان پاک نمی شوند.

پرس و جو داده ها بصورت آفلاین

پایگاه داده بیدرنگ Firebase داده های بازگشتی از یک درخواست را برای استفاده در حالت آفلاین ذخیره می کند. برای پرس و جوهایی که در حالت آفلاین ساخته می شوند، پایگاه داده بیدرنگ Firebase برای داده های بارگیری شده قبلی به کار خود ادامه می دهد. اگر داده‌های درخواستی بارگیری نشده باشند، پایگاه داده بیدرنگ Firebase داده‌ها را از حافظه پنهان محلی بارگیری می‌کند. هنگامی که اتصال شبکه دوباره در دسترس است، داده ها بارگیری می شوند و پرس و جو را منعکس می کنند.

به عنوان مثال، این کد برای چهار مورد آخر در پایگاه داده امتیازها جستجو می کند:

final scoresRef = FirebaseDatabase.instance.ref("scores");
scoresRef.orderByValue().limitToLast(4).onChildAdded.listen((event) {
  debugPrint("The ${event.snapshot.key} dinosaur's score is ${event.snapshot.value}.");
});

فرض کنید که کاربر ارتباط خود را قطع می کند، آفلاین می شود و برنامه را دوباره راه اندازی می کند. در حالی که هنوز آفلاین است، برنامه دو مورد آخر را از یک مکان جستجو می کند. این عبارت با موفقیت دو مورد آخر را برمی گرداند زیرا برنامه هر چهار مورد را در جستار بالا بارگیری کرده است.

scoresRef.orderByValue().limitToLast(2).onChildAdded.listen((event) {
  debugPrint("The ${event.snapshot.key} dinosaur's score is ${event.snapshot.value}.");
});

در مثال قبلی، سرویس گیرنده پایگاه داده بیدرنگ Firebase با استفاده از حافظه پنهان، رویدادهای «کودک اضافه شده» را برای دو دایناسور با بالاترین امتیاز افزایش می‌دهد. اما یک رویداد "ارزش" را افزایش نمی دهد، زیرا برنامه هرگز آن درخواست را در حالت آنلاین اجرا نکرده است.

اگر برنامه شش مورد آخر را در حالت آفلاین درخواست کند، بلافاصله رویدادهای «کودک اضافه شده» را برای چهار مورد ذخیره شده در حافظه پنهان دریافت می‌کند. هنگامی که دستگاه دوباره آنلاین می شود، سرویس گیرنده پایگاه داده بیدرنگ Firebase با سرور همگام می شود و دو رویداد نهایی «کودک اضافه شده» و «ارزش» را برای برنامه دریافت می کند.

انجام معاملات آفلاین

هر تراکنشی که در زمانی که برنامه آفلاین است انجام شود، در صف قرار می گیرد. هنگامی که برنامه دوباره اتصال شبکه را به دست آورد، تراکنش ها به سرور پایگاه داده بلادرنگ ارسال می شوند.

پایگاه داده Realtime Firebase دارای ویژگی های بسیاری برای مقابله با سناریوهای آفلاین و اتصال به شبکه است. بقیه این راهنما برای برنامه شما اعمال می‌شود، چه تداوم را فعال کرده باشید یا نه.

مدیریت حضور

در برنامه‌های بلادرنگ، تشخیص اتصال و قطع اتصال کلاینت‌ها اغلب مفید است. به عنوان مثال، ممکن است بخواهید زمانی که مشتری قطع می شود، کاربر را به عنوان "آفلاین" علامت گذاری کنید.

کلاینت های پایگاه داده Firebase ابتدایی های ساده ای را ارائه می دهند که می توانید از آنها برای نوشتن در پایگاه داده زمانی که کلاینت از سرورهای پایگاه داده Firebase جدا می شود استفاده کنید. این به‌روزرسانی‌ها چه اتصال کلاینت به‌طور تمیز قطع شود یا خیر، رخ می‌دهند، بنابراین می‌توانید برای پاک‌سازی داده‌ها به آنها اعتماد کنید، حتی اگر اتصال قطع شود یا کلاینت خراب شود. تمام عملیات نوشتن، از جمله تنظیم، به روز رسانی، و حذف، می تواند در صورت قطع اتصال انجام شود.

در اینجا یک مثال ساده از نوشتن داده در هنگام قطع اتصال با استفاده از onDisconnect ابتدایی آورده شده است:

final presenceRef = FirebaseDatabase.instance.ref("disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnect().set("I disconnected!");

چگونه onDisconnect کار می کند

هنگامی که یک عملیات onDisconnect() ایجاد می کنید، این عملیات در سرور پایگاه داده بیدرنگ Firebase زندگی می کند. سرور امنیت را بررسی می کند تا مطمئن شود کاربر می تواند رویداد نوشتن درخواستی را انجام دهد و در صورت نامعتبر بودن برنامه شما را به اطلاع می رساند. سپس سرور اتصال را کنترل می کند. اگر در هر نقطه ای زمان اتصال تمام شود، یا به طور فعال توسط سرویس گیرنده پایگاه داده Realtime بسته شود، سرور برای بار دوم امنیت را بررسی می کند (برای اطمینان از اینکه عملیات همچنان معتبر است) و سپس رویداد را فراخوانی می کند.

try {
    await presenceRef.onDisconnect().remove();
} catch (error) {
    debugPrint("Could not establish onDisconnect event: $error");
}

یک رویداد onDisconnect را نیز می توان با فراخوانی .cancel() لغو کرد:

final onDisconnectRef = presenceRef.onDisconnect();
onDisconnectRef.set("I disconnected");
// ...
// some time later when we change our minds
// ...
onDisconnectRef.cancel();

تشخیص وضعیت اتصال

برای بسیاری از ویژگی های مربوط به حضور، برای برنامه شما مفید است که بداند چه زمانی آنلاین یا آفلاین است. پایگاه داده بیدرنگ Firebase یک مکان ویژه در /.info/connected ارائه می دهد که هر بار که وضعیت اتصال سرویس گیرنده پایگاه داده بیدرنگ Firebase تغییر می کند، به روز می شود. در اینجا یک مثال است:

final connectedRef = FirebaseDatabase.instance.ref(".info/connected");
connectedRef.onValue.listen((event) {
  final connected = event.snapshot.value as bool? ?? false;
  if (connected) {
    debugPrint("Connected.");
  } else {
    debugPrint("Not connected.");
  }
});

/.info/connected یک مقدار بولی است که بین کلاینت‌های پایگاه داده بیدرنگ همگام‌سازی نمی‌شود، زیرا مقدار به وضعیت مشتری بستگی دارد. به عبارت دیگر، اگر یک کلاینت /.info/connected را به عنوان false بخواند، این تضمینی نیست که یک کلاینت جداگانه نیز false را بخواند.

رسیدگی به تاخیر

مهر زمانی سرور

سرورهای پایگاه داده بیدرنگ Firebase مکانیزمی را برای درج مُهرهای زمانی تولید شده روی سرور به عنوان داده فراهم می کنند. این ویژگی، همراه با onDisconnect ، راه آسانی را برای یادداشت‌برداری مطمئن از زمان قطع ارتباط مشتری پایگاه داده بیدرنگ ارائه می‌کند:

final userLastOnlineRef =
    FirebaseDatabase.instance.ref("users/joe/lastOnline");
userLastOnlineRef.onDisconnect().set(ServerValue.timestamp);

کج بودن ساعت

در حالی که ServerValue.timestamp بسیار دقیق تر و برای اکثر عملیات خواندن/نوشتن ارجح است، گاهی اوقات تخمین انحراف ساعت مشتری با توجه به سرورهای پایگاه داده بیدرنگ Firebase می تواند مفید باشد. می‌توانید یک تماس برگشتی را به مکان /.info/serverTimeOffset متصل کنید تا مقداری را که مشتریان پایگاه داده بیدرنگ Firebase بر حسب میلی‌ثانیه به زمان گزارش شده محلی (زمان دوره به میلی‌ثانیه) برای تخمین زمان سرور اضافه می‌کنند، به دست آورید. توجه داشته باشید که دقت این افست می‌تواند تحت‌تاثیر تأخیر شبکه قرار گیرد، و بنابراین اساساً برای کشف اختلافات بزرگ (> 1 ثانیه) در زمان ساعت مفید است.

final offsetRef = FirebaseDatabase.instance.ref(".info/serverTimeOffset");
offsetRef.onValue.listen((event) {
  final offset = event.snapshot.value as num? ?? 0.0;
  final estimatedServerTimeMs =
      DateTime.now().millisecondsSinceEpoch + offset;
});

نمونه برنامه حضور

با ترکیب عملیات قطع اتصال با نظارت بر وضعیت اتصال و مهرهای زمانی سرور، می توانید یک سیستم حضور کاربر بسازید. در این سیستم، هر کاربر داده‌ها را در یک مکان پایگاه داده ذخیره می‌کند تا مشخص کند آیا یک سرویس گیرنده پایگاه داده Realtime آنلاین است یا نه. مشتریان زمانی که آنلاین می‌شوند، این مکان را روی true و هنگام قطع ارتباط یک مهر زمانی تنظیم می‌کنند. این مهر زمان آخرین باری را که کاربر مورد نظر آنلاین بوده است نشان می دهد.

توجه داشته باشید که برنامه شما باید قبل از اینکه کاربر به صورت آنلاین علامت گذاری شود، عملیات قطع اتصال را در صف قرار دهد تا در صورت قطع شدن اتصال شبکه مشتری قبل از ارسال هر دو دستور به سرور، از هرگونه شرایط مسابقه جلوگیری شود.

// Since I can connect from multiple devices, we store each connection
// instance separately any time that connectionsRef's value is null (i.e.
// has no children) I am offline.
final myConnectionsRef =
    FirebaseDatabase.instance.ref("users/joe/connections");

// Stores the timestamp of my last disconnect (the last time I was seen online)
final lastOnlineRef =
    FirebaseDatabase.instance.ref("/users/joe/lastOnline");

final connectedRef = FirebaseDatabase.instance.ref(".info/connected");
connectedRef.onValue.listen((event) {
  final connected = event.snapshot.value as bool? ?? false;
  if (connected) {
    final con = myConnectionsRef.push();

    // When this device disconnects, remove it.
    con.onDisconnect().remove();

    // When I disconnect, update the last time I was seen online.
    lastOnlineRef.onDisconnect().set(ServerValue.timestamp);

    // Add this device to my connections list.
    // This value could contain info about the device or a timestamp too.
    con.set(true);
  }
});