แอปพลิเคชัน Firebase จะทำงานได้แม้แอปของคุณจะสูญเสียเครือข่ายชั่วคราว การเชื่อมต่อ นอกจากนี้ Firebase ยังมีเครื่องมือสำหรับ การยืนยันข้อมูลภายในเครื่อง ในการจัดการการตรวจหาบุคคลในบ้าน และการจัดการกับเวลาในการตอบสนอง
ความต่อเนื่องของดิสก์
แอป Firebase จะจัดการการหยุดชะงักของเครือข่ายชั่วคราวโดยอัตโนมัติ ข้อมูลแคชจะใช้งานได้ขณะที่ออฟไลน์และ Firebase จะส่งการเขียนซ้ำ เมื่อการเชื่อมต่อเครือข่ายกลับมาทำงานอีกครั้ง
เมื่อคุณเปิดใช้การคงอยู่ของดิสก์ แอปจะเขียนข้อมูลภายในเครื่องไปยัง อุปกรณ์ของคุณเพื่อให้แอปรักษาสถานะขณะออฟไลน์ได้แม้ว่าผู้ใช้จะ หรือระบบปฏิบัติการรีสตาร์ทแอป
คุณเปิดใช้การคงอยู่ของดิสก์ได้ด้วยโค้ดเพียงบรรทัดเดียว
Kotlin+KTX
Firebase.database.setPersistenceEnabled(true)
Java
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
พฤติกรรมอย่างต่อเนื่อง
เมื่อเปิดใช้การถาวร ข้อมูลทั้งหมดที่ไคลเอ็นต์ Firebase Realtime Database จะซิงค์ขณะที่ออนไลน์ยังคงอยู่ที่ดิสก์และพร้อมใช้งานแบบออฟไลน์ แม้ว่าผู้ใช้หรือระบบปฏิบัติการจะรีสตาร์ทแอปก็ตาม ซึ่งหมายความว่า แอปพลิเคชันจะทำงานเช่นเดียวกับที่ออนไลน์โดยใช้ข้อมูลในตัวเครื่องที่จัดเก็บในแคช Callback ของผู้ฟังจะยังคงเริ่มทำงานต่อไปเพื่ออัปเดตในพื้นที่
ไคลเอ็นต์ 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 MB ควรเป็น เพียงพอสำหรับแอปพลิเคชันส่วนใหญ่ หากแคชมีขนาดใหญ่กว่าขนาดที่กำหนดค่าไว้ Firebase Realtime Database จะล้างข้อมูลที่ใช้ล่าสุดออกถาวร โดยข้อมูลที่ซิงค์ไว้จะไม่ถูกลบออกจากแคชถาวร
การค้นหาข้อมูลแบบออฟไลน์
Firebase Realtime Database จัดเก็บข้อมูลที่แสดงผลจากการค้นหาสำหรับการใช้งาน เมื่อออฟไลน์ สำหรับการค้นหาที่สร้างขึ้นขณะออฟไลน์ Firebase Realtime Database จะยังคงทำงานต่อไปสำหรับข้อมูลที่โหลดก่อนหน้านี้ หากข้อมูลที่ขอไม่โหลด Firebase Realtime Database จะโหลด จากแคชในเครื่อง เมื่อการเชื่อมต่อเครือข่ายใช้งานได้อีกครั้ง จะโหลดข้อมูลและจะแสดงการค้นหา
ตัวอย่างเช่น โค้ดนี้จะสอบถามถึงพารามิเตอร์ 4 รายการใน 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()); } // ... });
สมมติว่าผู้ใช้ขาดการเชื่อมต่อ ออฟไลน์ และรีสตาร์ทแอป ขณะที่ออฟไลน์ แอปจะค้นหาสำหรับ 2 รายการสุดท้ายจาก สถานที่เดียวกัน การค้นหานี้จะแสดง 2 รายการสุดท้ายได้สำเร็จ เพราะแอปโหลดขึ้นมาทั้ง 4 รายการในการค้นหาด้านบน
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 เพิ่ม "เพิ่มเด็ก" เหตุการณ์สำหรับไดโนเสาร์ 2 ตัวที่ทำคะแนนสูงสุดโดยใช้ แคชที่เก็บไว้ แต่จะไม่เพิ่ม "ค่า" เนื่องจากแอป ไม่เคยดำเนินการค้นหานั้นขณะที่ออนไลน์
หากแอปจะขอรายการ 6 รายการล่าสุดขณะออฟไลน์ "เพิ่มเด็ก" เหตุการณ์ของทั้ง 4 รายการที่แคชไว้ได้ทันที เมื่อ อุปกรณ์กลับมาออนไลน์อีกครั้ง ไคลเอ็นต์ Firebase Realtime Database จะซิงค์ กับเซิร์ฟเวอร์ แล้วส่ง "เพิ่มเด็ก" 2 คนสุดท้าย และ "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!");
วิธีการทำงานของการยกเลิกการเชื่อมต่อ
เมื่อคุณสร้างการดำเนินการ onDisconnect()
อยู่ที่เซิร์ฟเวอร์ Firebase Realtime Database เซิร์ฟเวอร์จะตรวจสอบความปลอดภัยเพื่อ
ตรวจสอบว่าผู้ใช้สามารถทำกิจกรรมการเขียนตามที่ขอได้ แล้วแจ้งข้อมูล
ในแอปของคุณหากแอปไม่ถูกต้อง จากนั้นเซิร์ฟเวอร์
ติดตามดูการเชื่อมต่อ หากการเชื่อมต่อหมดเวลา หรือ
มีการปิดอย่างต่อเนื่องโดยไคลเอ็นต์ Realtime Database เซิร์ฟเวอร์จะตรวจสอบความปลอดภัย
ครั้งที่ 2 (เพื่อให้มั่นใจว่าการดำเนินการยังคงถูกต้อง) แล้วจึงเรียกใช้
กิจกรรมนั้น
แอปของคุณสามารถใช้ Callback ในการดำเนินการเขียน
เพื่อตรวจสอบว่าการแนบ 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 คุณ
สามารถแนบ Callback ไปยังตำแหน่ง /.info/serverTimeOffset
เพื่อรับค่าเป็นมิลลิวินาทีที่ไคลเอ็นต์ Firebase Realtime Database
เพิ่มลงในเวลาที่รายงานในท้องถิ่น (เวลา Epoch ในหน่วยมิลลิวินาที) เพื่อประมาณการ
เวลาของเซิร์ฟเวอร์ โปรดทราบว่าความแม่นยำของออฟเซ็ตนี้อาจได้รับผลกระทบจาก
เวลาในการตอบสนองของเครือข่าย และ มีประโยชน์สำหรับการค้นพบ
เวลาของนาฬิกามีความคลาดเคลื่อนมาก (> 1 วินาที)
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"); } });