Ứng dụng Firebase hoạt động ngay cả khi ứng dụng của bạn tạm thời mất mạng kết nối. Ngoài ra, Firebase còn cung cấp các công cụ để lưu trữ cục bộ dữ liệu, quản lý sự hiện diện và xử lý độ trễ.
Khả năng lưu trữ cố định ổ đĩa
Các ứng dụng Firebase tự động xử lý các trường hợp gián đoạn mạng tạm thời. Dữ liệu đã lưu vào bộ nhớ đệm chỉ dùng được khi không có mạng và Firebase sẽ gửi lại mọi lượt ghi khi kết nối mạng được khôi phục.
Khi bạn bật tính năng lưu trữ cố định ổ đĩa, ứng dụng sẽ ghi dữ liệu cục bộ vào thiết bị để ứng dụng của bạn có thể duy trì trạng thái khi không có kết nối mạng, ngay cả khi người dùng hoặc hệ điều hành sẽ khởi động lại ứng dụng.
Bạn có thể bật tính năng lưu trữ cố định ổ đĩa chỉ bằng một dòng mã.
FirebaseDatabase.instance.setPersistenceEnabled(true);
Hành vi liên tục
Khi bật tính năng lưu trữ cố định, mọi dữ liệu mà ứng dụng Cơ sở dữ liệu theo thời gian thực Firebase sẽ đồng bộ hoá khi vẫn có kết nối mạng và duy trì vào ổ đĩa và có thể sử dụng khi không có mạng, ngay cả khi người dùng hoặc hệ điều hành khởi động lại ứng dụng. Điều này có nghĩa là ứng dụng hoạt động giống như hoạt động trực tuyến bằng cách sử dụng dữ liệu cục bộ được lưu trữ trong bộ nhớ đệm. Lệnh gọi lại trình nghe sẽ tiếp tục kích hoạt để cập nhật cục bộ.
Ứng dụng Cơ sở dữ liệu theo thời gian thực Firebase sẽ tự động xếp hàng đợi tất cả thao tác ghi được thực hiện khi ứng dụng của bạn không có kết nối mạng. Khi bật tính năng lưu trữ cố định, hàng đợi này cũng được duy trì vào ổ đĩa để tất cả khi người dùng hoặc hệ điều hành sẽ khởi động lại ứng dụng. Khi ứng dụng kết nối lại, tất cả các hoạt động sẽ được gửi đến máy chủ Cơ sở dữ liệu theo thời gian thực Firebase.
Nếu ứng dụng của bạn sử dụng tính năng Xác thực Firebase, ứng dụng Cơ sở dữ liệu theo thời gian thực Firebase duy trì trạng thái xác thực của người dùng mã thông báo khi ứng dụng khởi động lại. Nếu mã thông báo xác thực hết hạn trong khi ứng dụng không có kết nối mạng, thì ứng dụng sẽ tạm dừng ghi cho đến khi ứng dụng của bạn xác thực lại người dùng, nếu không thì có thể không thực hiện được thao tác ghi do các quy tắc bảo mật.
Luôn cập nhật dữ liệu
Cơ sở dữ liệu theo thời gian thực của Firebase đồng bộ hoá và lưu trữ cục bộ một bản sao của dữ liệu cho trình nghe đang hoạt động. Ngoài ra, bạn có thể giữ lại các vị trí cụ thể đang đồng bộ hoá.
final scoresRef = FirebaseDatabase.instance.ref("scores");
scoresRef.keepSynced(true);
Ứng dụng Cơ sở dữ liệu theo thời gian thực Firebase tự động tải dữ liệu xuống tại các vị trí này và tiếp tục đồng bộ hoá ngay cả khi tham chiếu không có trình nghe đang hoạt động. Bạn có thể tắt tính năng đồng bộ hoá bằng dòng mã sau.
scoresRef.keepSynced(false);
Theo mặc định, 10MB dữ liệu đã đồng bộ hoá trước đó sẽ được lưu vào bộ nhớ đệm. Thông tin này phải là là đủ cho hầu hết các ứng dụng. Nếu bộ nhớ đệm vượt quá kích thước đã định cấu hình, Cơ sở dữ liệu theo thời gian thực của Firebase sẽ xoá hoàn toàn dữ liệu được sử dụng gần đây nhất. Dữ liệu được đồng bộ hoá sẽ không bị xoá hoàn toàn khỏi bộ nhớ đệm.
Truy vấn dữ liệu ngoại tuyến
Cơ sở dữ liệu theo thời gian thực của Firebase lưu trữ dữ liệu được trả về từ một truy vấn để sử dụng khi không có kết nối mạng. Đối với các truy vấn được tạo khi ngoại tuyến, Cơ sở dữ liệu theo thời gian thực của Firebase vẫn tiếp tục hoạt động đối với dữ liệu đã tải trước đó. Nếu dữ liệu bạn yêu cầu chưa tải, thì Cơ sở dữ liệu theo thời gian thực của Firebase sẽ tải dữ liệu từ bộ nhớ đệm cục bộ. Khi kết nối mạng có sẵn trở lại, dữ liệu sẽ tải và sẽ phản ánh truy vấn.
Ví dụ: đoạn mã này truy vấn bốn mục cuối cùng trong cơ sở dữ liệu điểm số:
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}.");
});
Giả sử rằng người dùng mất kết nối, mất kết nối mạng và khởi động lại ứng dụng. Khi vẫn ở chế độ ngoại tuyến, các truy vấn ứng dụng đối với hai mục cuối cùng từ cùng một vị trí. Truy vấn này sẽ trả về thành công hai mục cuối cùng vì ứng dụng đã tải cả 4 mục trong truy vấn trên.
scoresRef.orderByValue().limitToLast(2).onChildAdded.listen((event) {
debugPrint("The ${event.snapshot.key} dinosaur's score is ${event.snapshot.value}.");
});
Trong ví dụ trước, ứng dụng Cơ sở dữ liệu theo thời gian thực Firebase tăng "đã thêm trẻ em" cho hai con khủng long có điểm số cao nhất bằng cách sử dụng bộ nhớ đệm cố định. Nhưng sẽ không làm tăng "giá trị" vì ứng dụng đã không bao giờ thực thi truy vấn đó khi trực tuyến.
Nếu ứng dụng yêu cầu sáu mục cuối cùng khi không có kết nối mạng, ứng dụng sẽ nhận được "đã thêm trẻ em" sự kiện cho bốn mục được lưu vào bộ nhớ đệm ngay lập tức. Khi thiết bị của bạn trở lại trực tuyến, ứng dụng Cơ sở dữ liệu thời gian thực Firebase đồng bộ hoá với máy chủ và nhận được hai "con thêm" cuối cùng và "value" các sự kiện cho ứng dụng.
Xử lý giao dịch ngoại tuyến
Mọi giao dịch được thực hiện khi ứng dụng không có kết nối mạng sẽ được đưa vào hàng đợi. Sau khi ứng dụng có lại kết nối mạng, các giao dịch sẽ được gửi đến máy chủ Cơ sở dữ liệu theo thời gian thực.
Cơ sở dữ liệu theo thời gian thực của Firebase có nhiều tính năng giúp xử lý dữ liệu ngoại tuyến và kết nối mạng. Phần còn lại của hướng dẫn này áp dụng cho ứng dụng của bạn cho dù bạn có bật tính năng ổn định hay không.
Quản lý sự hiện diện
Trong các ứng dụng thời gian thực, thường hữu ích trong việc phát hiện khi nào ứng dụng kết nối và ngắt kết nối. Ví dụ: bạn có thể muốn đánh dấu người dùng là 'ngoại tuyến' khi khách hàng của họ ngắt kết nối.
Ứng dụng Cơ sở dữ liệu Firebase cung cấp các dữ liệu gốc đơn giản mà bạn có thể sử dụng để ghi vào cơ sở dữ liệu khi ứng dụng ngắt kết nối khỏi Cơ sở dữ liệu Firebase máy chủ. Các quá trình cập nhật này diễn ra dù máy khách có ngắt kết nối một cách dễ dàng hay không, để bạn có thể dựa vào các dịch vụ này để dọn dẹp dữ liệu ngay cả khi mất kết nối hoặc ứng dụng gặp sự cố. Tất cả thao tác ghi, bao gồm cả thao tác đặt, cập nhật và xoá có thể được thực hiện khi ngắt kết nối.
Dưới đây là một ví dụ đơn giản về cách ghi dữ liệu khi bị ngắt kết nối bằng cách sử dụng
Dữ liệu gốc onDisconnect
:
final presenceRef = FirebaseDatabase.instance.ref("disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnect().set("I disconnected!");
Cách tính năng onNgắt kết nối hoạt động
Khi bạn thiết lập một toán tử onDisconnect()
, toán tử
có trên máy chủ Cơ sở dữ liệu theo thời gian thực Firebase. Máy chủ kiểm tra bảo mật để
đảm bảo người dùng có thể thực hiện sự kiện ghi theo yêu cầu và thông báo
ứng dụng của bạn nếu ứng dụng đó không hợp lệ. Sau đó, máy chủ
sẽ giám sát kết nối. Nếu tại bất kỳ thời điểm nào kết nối hết thời gian chờ, hoặc
được chủ động đóng bởi ứng dụng Cơ sở dữ liệu theo thời gian thực, máy chủ sẽ kiểm tra bảo mật
lần thứ hai (để đảm bảo thao tác vẫn hợp lệ) rồi gọi
sự kiện.
try {
await presenceRef.onDisconnect().remove();
} catch (error) {
debugPrint("Could not establish onDisconnect event: $error");
}
Bạn cũng có thể huỷ sự kiện onNgắt kết nối bằng cách gọi .cancel()
:
final onDisconnectRef = presenceRef.onDisconnect();
onDisconnectRef.set("I disconnected");
// ...
// some time later when we change our minds
// ...
onDisconnectRef.cancel();
Phát hiện trạng thái kết nối
Đối với nhiều tính năng liên quan đến sự hiện diện, tính năng này rất hữu ích cho ứng dụng của bạn
biết khi nào thiết bị trực tuyến hoặc ngoại tuyến. Cơ sở dữ liệu theo thời gian thực của Firebase
cung cấp một vị trí đặc biệt tại /.info/connected
được cập nhật mỗi khi trạng thái kết nối của ứng dụng Cơ sở dữ liệu theo thời gian thực Firebase
thay đổi. Bạn có thể tham khảo ví dụ sau đây:
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
là một giá trị boolean không
được đồng bộ hoá giữa các ứng dụng Cơ sở dữ liệu theo thời gian thực vì giá trị là
phụ thuộc vào trạng thái của khách hàng. Nói cách khác, nếu một khách hàng
đọc /.info/connected
là false, giá trị này là không
đảm bảo rằng một ứng dụng riêng biệt cũng sẽ đọc giá trị "false".
Độ trễ xử lý
Dấu thời gian của máy chủ
Máy chủ Cơ sở dữ liệu theo thời gian thực Firebase cung cấp cơ chế chèn
dấu thời gian được tạo trên máy chủ dưới dạng dữ liệu. Tính năng này, kết hợp với
onDisconnect
, giúp bạn dễ dàng ghi chú một cách đáng tin cậy
thời điểm ứng dụng Cơ sở dữ liệu theo thời gian thực ngắt kết nối:
final userLastOnlineRef =
FirebaseDatabase.instance.ref("users/joe/lastOnline");
userLastOnlineRef.onDisconnect().set(ServerValue.timestamp);
Mặt đồng hồ
Trong khi ServerValue.timestamp
thì hiệu quả hơn nhiều
chính xác và phù hợp nhất với hầu hết các thao tác đọc/ghi,
Đôi khi, việc ước tính độ lệch đồng hồ của ứng dụng khách với
so với máy chủ của Cơ sở dữ liệu theo thời gian thực Firebase. Bạn
có thể đính kèm lệnh gọi lại vào vị trí /.info/serverTimeOffset
để nhận được giá trị (tính bằng mili giây) mà ứng dụng Cơ sở dữ liệu thời gian thực Firebase
thêm vào thời gian được báo cáo cục bộ (thời gian bắt đầu của hệ thống tính bằng mili giây) để ước tính
theo thời gian máy chủ. Lưu ý rằng độ chính xác của giá trị bù trừ này có thể bị ảnh hưởng bởi
độ trễ kết nối mạng, nên công cụ này chủ yếu hữu ích trong việc khám phá
chênh lệch lớn (> 1 giây) về thời gian đồng hồ.
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;
});
Ứng dụng mẫu hiện diện
Bằng cách kết hợp các hoạt động ngắt kết nối với tính năng theo dõi trạng thái kết nối và dấu thời gian của máy chủ, bạn có thể xây dựng một hệ thống hiện diện người dùng. Trong hệ thống này, mỗi người dùng lưu trữ dữ liệu tại một vị trí cơ sở dữ liệu để cho biết liệu có Ứng dụng Cơ sở dữ liệu theo thời gian thực đang trực tuyến. Ứng dụng đặt vị trí này thành true khi khi các thiết bị này kết nối mạng và một dấu thời gian khi chúng ngắt kết nối. Dấu thời gian này cho biết lần cuối cùng người dùng cụ thể trực tuyến.
Lưu ý rằng ứng dụng phải đưa các hoạt động ngắt kết nối vào hàng đợi trước khi người dùng được đánh dấu là trực tuyến, để tránh mọi điều kiện tranh đấu trong trường hợp khách hàng bị mất kết nối mạng trước khi có thể gửi cả hai lệnh đến máy chủ.
// 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);
}
});