تعمل تطبيقات Firebase حتى إذا فقد تطبيقك الشبكة مؤقتًا. الاتصال. بالإضافة إلى ذلك، يوفر Firebase أدوات للاحتفاظ بالبيانات محليًا، وإدارة التواجد ووقت الاستجابة.
ثبات القرص
تتعامل تطبيقات Firebase مع الانقطاعات المؤقتة في الشبكة تلقائيًا. تتوفّر البيانات المخزّنة مؤقتًا عندما تكون غير متصل بالإنترنت، ويعيد Firebase إرسال أي عمليات كتابة. عند استعادة اتصال الشبكة.
عند تفعيل خاصية الاحتفاظ بالقرص، يكتب تطبيقك البيانات محليًا على حتى يحافظ تطبيقك على حالته أثناء عدم الاتصال بالإنترنت، حتى إذا كان المستخدم أو نظام التشغيل يعيد تشغيل التطبيق.
يمكنك تفعيل ميزة تثبيت القرص باستخدام سطر واحد فقط من الرمز.
Kotlin+KTX
Firebase.database.setPersistenceEnabled(true)
Java
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
سلوك الاستمرارية
من خلال تفعيل ميزة الاحتفاظ بالبيانات، ستظهر أي بيانات يجريها عميل Firebase Realtime Database. تتم مزامنته أثناء استمرار الاتصال بالإنترنت على القرص وإتاحتها في وضع عدم الاتصال، حتى عندما يعيد المستخدم أو نظام التشغيل تشغيل التطبيق. هذا يعني أن كما لو كان على الإنترنت باستخدام البيانات المحلية المخزنة في ذاكرة التخزين المؤقت. سيستمر تنشيط استدعاءات المستمعين للحصول على التحديثات المحلية.
يحتفظ عميل Firebase Realtime Database تلقائيًا بقائمة انتظار لجميع كتابة العمليات التي يتم إجراؤها أثناء عدم اتصال التطبيق بالإنترنت. عند تمكين الثبات، يتم أيضًا حفظ قائمة الانتظار هذه على القرص حتى يكون جميع عندما تتوفر كتاباتك عندما يستخدم المستخدم أو نظام التشغيل لإعادة تشغيل التطبيق. عندما يستعيد التطبيق الاتصال، فإن جميع يتم إرسال العمليات إلى خادم Firebase Realtime Database.
إذا كان تطبيقك يستخدم مصادقة Firebase، يستمر عميل Firebase Realtime Database في مواصلة مصادقة المستخدم. الرمز المميز عبر عمليات إعادة تشغيل التطبيق. إذا انتهت صلاحية الرمز المميّز للمصادقة عندما يكون تطبيقك غير متصل بالإنترنت، سيتم إيقاف البرنامج مؤقتًا. كتابة العمليات حتى يعيد التطبيق مصادقة المستخدم، وإلا عمليات الكتابة بسبب قواعد الأمان.
الحفاظ على إعادة تحميل البيانات
يعمل Firebase Realtime Database على مزامنة وتخزين نسخة محلية من المستمعين النشطين. بالإضافة إلى ذلك، يمكنك الاحتفاظ بمواقع جغرافية محددة متزامنًا.
Kotlin+KTX
val scoresRef = Firebase.database.getReference("scores") scoresRef.keepSynced(true)
Java
DatabaseReference scoresRef = FirebaseDatabase.getInstance().getReference("scores"); scoresRef.keepSynced(true);
يعمل عميل Firebase Realtime Database على تنزيل البيانات تلقائيًا في هذه المواقع ويحافظ على مزامنتها حتى إذا كان المرجع المستمعين النشطين. يمكنك إيقاف المزامنة مرة أخرى باستخدام السطر التالي من التعليمة البرمجية.
Kotlin+KTX
scoresRef.keepSynced(false)
Java
scoresRef.keepSynced(false);
بشكل تلقائي، يتم تخزين 10 ميغابايت من البيانات التي تمت مزامنتها سابقًا مؤقتًا. يجب أن يكون هذا كافيًا لمعظم التطبيقات. إذا تخطت ذاكرة التخزين المؤقت حجمها الذي تم إعداده، تزيل Firebase Realtime Database نهائيًا البيانات التي تم استخدامها مؤخرًا. لا تتم الإزالة النهائية للبيانات التي يتم الاحتفاظ بها متزامنة من ذاكرة التخزين المؤقت.
الاستعلام عن البيانات بلا اتصال بالإنترنت
تخزِّن Firebase Realtime Database البيانات التي يتم عرضها من خلال طلب بحث لاستخدامها. عندما تكون غير متصل بالإنترنت. بالنسبة للاستعلامات التي تم إنشاؤها أثناء وضع عدم الاتصال، تواصل Firebase Realtime Database العمل مع البيانات التي تم تحميلها سابقًا. إذا لم يتم تحميل البيانات المطلوبة، يتم تحميل Firebase Realtime Database. من ذاكرة التخزين المؤقت المحلية. عندما يكون اتصال الشبكة متاحًا مرة أخرى، يتم تحميل البيانات وستعكس الاستعلام.
على سبيل المثال، تطلب هذه التعليمة البرمجية لآخر أربعة عناصر في Firebase Realtime Database من النتائج
Kotlin+KTX
val scoresRef = Firebase.database.getReference("scores") scoresRef.orderByValue().limitToLast(4).addChildEventListener(object : ChildEventListener { override fun onChildAdded(snapshot: DataSnapshot, previousChild: String?) { Log.d(TAG, "The ${snapshot.key} dinosaur's score is ${snapshot.value}") } // ... })
Java
DatabaseReference scoresRef = FirebaseDatabase.getInstance().getReference("scores"); scoresRef.orderByValue().limitToLast(4).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(@NonNull DataSnapshot snapshot, String previousChild) { Log.d(TAG, "The " + snapshot.getKey() + " dinosaur's score is " + snapshot.getValue()); } // ... });
لنفترض أنّ المستخدم يفقد الاتصال بالإنترنت ويتوقّف عن الاتصال بالإنترنت ويعيد تشغيل التطبيق. أثناء عدم اتصال التطبيق بالإنترنت، يطلب التطبيق آخر عنصرين من الموقع نفسه. سيعرض هذا الاستعلام آخر عنصرين بنجاح لأن التطبيق حمّل جميع العناصر الأربعة في الاستعلام أعلاه.
Kotlin+KTX
scoresRef.orderByValue().limitToLast(2).addChildEventListener(object : ChildEventListener { override fun onChildAdded(snapshot: DataSnapshot, previousChild: String?) { Log.d(TAG, "The ${snapshot.key} dinosaur's score is ${snapshot.value}") } // ... })
Java
scoresRef.orderByValue().limitToLast(2).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(@NonNull DataSnapshot snapshot, String previousChild) { Log.d(TAG, "The " + snapshot.getKey() + " dinosaur's score is " + snapshot.getValue()); } // ... });
في المثال السابق، رفع العميل Firebase Realtime Database "تمت إضافة تابعة" التي تضم أعلى ديناصورين من النقاط، وذلك باستخدام تم الاحتفاظ بذاكرة التخزين المؤقت. لكنها لن تزيد "القيمة" حدث، نظرًا لأن التطبيق يحتوي على لم تنفذ هذا الاستعلام أثناء الاتصال بالإنترنت.
إذا طلب التطبيق العناصر الستة الأخيرة أثناء عدم الاتصال، فسيحصل "تمت إضافة تابعة" الأحداث للعناصر الأربعة المخزنة مؤقتًا على الفور. عندما إعادة اتصال الجهاز بالإنترنت، تتم مزامنة برنامج Firebase Realtime Database مع الخادم ويتم الحصول على آخر عنصرين "تابعين" و 'value' أحداث للتطبيق.
التعامل مع المعاملات بلا إنترنت
يتم وضع أي معاملات يتم إجراؤها عندما يكون التطبيق بلا اتصال بالإنترنت في قائمة الانتظار. بعد أن يستعيد التطبيق الاتصال بالشبكة، يتم إرسال المعاملات إلى خادم Realtime Database.
إدارة التواجد
غالبًا ما يكون من المفيد في تطبيقات الوقت الفعلي اكتشاف الوقت الذي يستغرقه العملاء الاتصال وقطع الاتصال. على سبيل المثال، يمكنك أن تريد وضع علامة "غير متصل" على المستخدم عندما ينقطع اتصال عميله.
يوفر عملاء قاعدة بيانات Firebase أساسيات بسيطة يمكنك استخدامها الكتابة في قاعدة البيانات عندما ينقطع اتصال العميل بقاعدة بيانات Firebase الخوادم. وتحدث هذه التحديثات سواء انفصل العميل عن الخدمة أم لا لذا يمكنك الاعتماد عليها لتنظيف البيانات حتى إذا انقطع الاتصال أو تعطل عميل ما. جميع عمليات الكتابة، بما في ذلك الإعداد وتحديثه وإزالته، عند قطع الاتصال.
فيما يلي مثال بسيط لكتابة البيانات عند الفصل باستخدام
المجموعة الأساسية onDisconnect
:
Kotlin+KTX
val presenceRef = Firebase.database.getReference("disconnectmessage") // Write a string when this client loses connection presenceRef.onDisconnect().setValue("I disconnected!")
Java
DatabaseReference presenceRef = FirebaseDatabase.getInstance().getReference("disconnectmessage"); // Write a string when this client loses connection presenceRef.onDisconnect().setValue("I disconnected!");
طريقة عمل ميزة on Connect
عند إنشاء عملية onDisconnect()
، يتم
يوجد على خادم Firebase Realtime Database. يفحص الخادم الأمان
وتتأكد من أن المستخدم يمكنه تنفيذ حدث الكتابة المطلوب، ويبلغ
تطبيقك إذا كان غير صالح. ثم الخادم
ويراقب الاتصال. إذا انتهت مهلة الاتصال في أي وقت أو
بشكل نشط من قِبل عميل Realtime Database، يفحص الخادم الأمان
مرة ثانية (للتأكد من أن العملية لا تزال صالحة) ثم يتم استدعاء
الحدث.
يمكن لتطبيقك استخدام الاستدعاء في عملية الكتابة.
للتأكّد من توصيل onDisconnect
بشكل صحيح:
Kotlin+KTX
presenceRef.onDisconnect().removeValue { error, reference -> error?.let { Log.d(TAG, "could not establish onDisconnect event: ${error.message}") } }
Java
presenceRef.onDisconnect().removeValue(new DatabaseReference.CompletionListener() { @Override public void onComplete(DatabaseError error, @NonNull DatabaseReference reference) { if (error != null) { Log.d(TAG, "could not establish onDisconnect event:" + error.getMessage()); } } });
يمكن أيضًا إلغاء حدث "onDisconnect
" من خلال الاتصال بالرقم .cancel()
:
Kotlin+KTX
val onDisconnectRef = presenceRef.onDisconnect() onDisconnectRef.setValue("I disconnected") // ... // some time later when we change our minds // ... onDisconnectRef.cancel()
Java
OnDisconnect onDisconnectRef = presenceRef.onDisconnect(); onDisconnectRef.setValue("I disconnected"); // ... // some time later when we change our minds // ... onDisconnectRef.cancel();
اكتشاف حالة الاتصال
بالنسبة إلى العديد من الميزات المتعلّقة بالحضور، يكون ذلك مفيدًا لتطبيقك.
لمعرفة ما إذا كان متصلاً بالإنترنت أو غير متصل بالإنترنت. Firebase Realtime Database
يوفر موقعًا خاصًا في /.info/connected
والذي
يتم تعديل كل مرة يتم فيها تعديل حالة اتصال عميل Firebase Realtime Database
التغييرات. وفي ما يلي مثال لذلك:
Kotlin+KTX
val connectedRef = Firebase.database.getReference(".info/connected") connectedRef.addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { val connected = snapshot.getValue(Boolean::class.java) ?: false if (connected) { Log.d(TAG, "connected") } else { Log.d(TAG, "not connected") } } override fun onCancelled(error: DatabaseError) { Log.w(TAG, "Listener was cancelled") } })
Java
DatabaseReference connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected"); connectedRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { boolean connected = snapshot.getValue(Boolean.class); if (connected) { Log.d(TAG, "connected"); } else { Log.d(TAG, "not connected"); } } @Override public void onCancelled(@NonNull DatabaseError error) { Log.w(TAG, "Listener was cancelled"); } });
/.info/connected
هي قيمة منطقية ليست
تمت مزامنتها بين Realtime Database من العملاء لأن القيمة
يعتمد على حالة العميل. بعبارة أخرى، إذا كان أحد العملاء
تقرأ /.info/connected
على أنها false، هذا لا
ضمان قراءة عميل منفصل للخطأ أيضًا.
على نظام التشغيل Android، يدير Firebase تلقائيًا حالة الاتصال من أجل
لتقليل معدل نقل البيانات واستخدام البطارية. عندما لا يكون لدى العميل مستمعون نشطون،
ما مِن كتابة في انتظار المراجعة أو onDisconnect
عملياتها، ولا يتم فصلها بشكل صريح من خلال
goOffline
،
يغلق Firebase الاتصال بعد 60 ثانية من عدم النشاط.
وقت الاستجابة
الطوابع الزمنية للخادم
توفر خوادم Firebase Realtime Database آلية لإدراج
الطوابع الزمنية التي تم إنشاؤها على الخادم كبيانات. وهذه الميزة بالإضافة إلى
onDisconnect
، طريقة سهلة لتدوين الملاحظات بشكل موثوق فيه
الوقت الذي تم فيه قطع اتصال عميل Realtime Database:
Kotlin+KTX
val userLastOnlineRef = Firebase.database.getReference("users/joe/lastOnline") userLastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP)
Java
DatabaseReference userLastOnlineRef = FirebaseDatabase.getInstance().getReference("users/joe/lastOnline"); userLastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP);
انحراف الساعة
في حين أن firebase.database.ServerValue.TIMESTAMP
أكثر بكثير
ودقيقة ومفضلة لمعظم عمليات القراءة/الكتابة،
قد يكون من المفيد أحيانًا تقدير ساعة العميل
في ما يتعلق بخوادم Firebase Realtime Database. إِنْتَ
يمكن إرفاق معاودة الاتصال بالموقع الجغرافي /.info/serverTimeOffset
.
للحصول على القيمة، بالمللي ثانية، التي يستخدمها عملاء Firebase Realtime Database
تضيفه إلى الوقت المحلي المبلّغ عنه (وقت الحقبة بالمللي ثانية) لتقدير
وقت الخادم. لاحظ أن دقة هذه الإزاحة يمكن أن تتأثر
وقت استجابة الشبكة، لذا فهي مفيدة في المقام الأول لاكتشاف
اختلافات كبيرة (أكبر من ثانية واحدة) في وقت الساعة.
Kotlin+KTX
val offsetRef = Firebase.database.getReference(".info/serverTimeOffset") offsetRef.addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { val offset = snapshot.getValue(Double::class.java) ?: 0.0 val estimatedServerTimeMs = System.currentTimeMillis() + offset } override fun onCancelled(error: DatabaseError) { Log.w(TAG, "Listener was cancelled") } })
Java
DatabaseReference offsetRef = FirebaseDatabase.getInstance().getReference(".info/serverTimeOffset"); offsetRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { double offset = snapshot.getValue(Double.class); double estimatedServerTimeMs = System.currentTimeMillis() + offset; } @Override public void onCancelled(@NonNull DatabaseError error) { Log.w(TAG, "Listener was cancelled"); } });
نموذج تطبيق التواجد
من خلال الجمع بين عمليات قطع الاتصال ومراقبة حالة الاتصال الطوابع الزمنية للخادم، فيمكنك إنشاء نظام تواجد المستخدم. في هذا النظام، يقوم كل مستخدم بتخزين البيانات في موقع قاعدة البيانات للإشارة إلى ما إذا كان عميل واحد (Realtime Database) متصل بالإنترنت. يضبط العملاء هذا الموقع على "صحيح" عندما عند اتصالهم بالإنترنت وبطابع زمني عند قطع الاتصال. هذا الطابع الزمني تشير إلى آخر مرة كان فيها المستخدم المحدد متصلاً بالإنترنت.
تجدر الإشارة إلى أنّ تطبيقك يجب أن يضع عمليات إلغاء الربط في قائمة انتظار قبل أن يبدأ المستخدم وتمييزها عبر الإنترنت، لتجنب أي شروط سباق في حال انعقاد يتم فقدان اتصال الشبكة قبل إرسال كلا الأمرين إلى الخادم.
إليك نظام بسيط لتواجد المستخدم:
Kotlin+KTX
// 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 val database = Firebase.database val myConnectionsRef = database.getReference("users/joe/connections") // Stores the timestamp of my last disconnect (the last time I was seen online) val lastOnlineRef = database.getReference("/users/joe/lastOnline") val connectedRef = database.getReference(".info/connected") connectedRef.addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { val connected = snapshot.getValue<Boolean>() ?: false if (connected) { val con = myConnectionsRef.push() // When this device disconnects, remove it con.onDisconnect().removeValue() // When I disconnect, update the last time I was seen online lastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP) // Add this device to my connections list // this value could contain info about the device or a timestamp too con.setValue(java.lang.Boolean.TRUE) } } override fun onCancelled(error: DatabaseError) { Log.w(TAG, "Listener was cancelled at .info/connected") } })
Java
// 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 FirebaseDatabase database = FirebaseDatabase.getInstance(); final DatabaseReference myConnectionsRef = database.getReference("users/joe/connections"); // Stores the timestamp of my last disconnect (the last time I was seen online) final DatabaseReference lastOnlineRef = database.getReference("/users/joe/lastOnline"); final DatabaseReference connectedRef = database.getReference(".info/connected"); connectedRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { boolean connected = snapshot.getValue(Boolean.class); if (connected) { DatabaseReference con = myConnectionsRef.push(); // When this device disconnects, remove it con.onDisconnect().removeValue(); // When I disconnect, update the last time I was seen online lastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP); // Add this device to my connections list // this value could contain info about the device or a timestamp too con.setValue(Boolean.TRUE); } } @Override public void onCancelled(@NonNull DatabaseError error) { Log.w(TAG, "Listener was cancelled at .info/connected"); } });