Cloud Firestore hỗ trợ lưu trữ dữ liệu ngoại tuyến. Tính năng này lưu trữ bản sao dữ liệu Cloud Firestore mà ứng dụng của bạn đang sử dụng tích cực để ứng dụng của bạn có thể truy cập dữ liệu khi thiết bị ngoại tuyến. Bạn có thể viết, đọc, nghe và truy vấn dữ liệu được lưu trong bộ nhớ đệm. Khi thiết bị trực tuyến trở lại, Cloud Firestore sẽ đồng bộ hóa mọi thay đổi cục bộ do ứng dụng của bạn thực hiện với chương trình phụ trợ của Cloud Firestore.
Để sử dụng tính năng lưu trữ ngoại tuyến, bạn không cần thực hiện bất kỳ thay đổi nào đối với mã mà bạn sử dụng để truy cập dữ liệu Cloud Firestore. Khi bật tính năng lưu trữ ngoại tuyến, thư viện máy khách Cloud Firestore sẽ tự động quản lý việc truy cập dữ liệu trực tuyến và ngoại tuyến, đồng thời đồng bộ hóa dữ liệu cục bộ khi thiết bị trực tuyến trở lại.
Định cấu hình tính kiên trì ngoại tuyến
Khi bạn khởi chạy Cloud Firestore, bạn có thể bật hoặc tắt tính năng lưu trữ ngoại tuyến:
- Đối với nền tảng Android và Apple, tính năng lưu trữ ngoại tuyến được bật theo mặc định. Để vô hiệu hóa tính bền vững, hãy đặt tùy chọn
PersistenceEnabled
thànhfalse
. - Đối với web, tính năng lưu trữ ngoại tuyến bị tắt theo mặc định. Để kích hoạt tính bền vững, hãy gọi phương thức
enablePersistence
. Bộ nhớ đệm của Cloud Firestore không tự động bị xóa giữa các phiên. Do đó, nếu ứng dụng web của bạn xử lý thông tin nhạy cảm, hãy đảm bảo hỏi người dùng xem họ có đang sử dụng thiết bị đáng tin cậy hay không trước khi bật tính năng lưu giữ lâu dài.
Web modular API
// Memory cache is the default if no config is specified.
initializeFirestore(app);
// This is the default behavior if no persistence is specified.
initializeFirestore(app, {localCache: memoryLocalCache()});
// Defaults to single-tab persistence if no tab manager is specified.
initializeFirestore(app, {localCache: persistentLocalCache(/*settings*/{})});
// Same as `initializeFirestore(app, {localCache: persistentLocalCache(/*settings*/{})})`,
// but more explicit about tab management.
initializeFirestore(app,
{localCache:
persistentLocalCache(/*settings*/{tabManager: persistentSingleTabManager()})
});
// Use multi-tab IndexedDb persistence.
initializeFirestore(app,
{localCache:
persistentLocalCache(/*settings*/{tabManager: persistentMultipleTabManager()})
});
Web namespaced API
firebase.firestore().enablePersistence() .catch((err) => { if (err.code == 'failed-precondition') { // Multiple tabs open, persistence can only be enabled // in one tab at a a time. // ... } else if (err.code == 'unimplemented') { // The current browser does not support all of the // features required to enable persistence // ... } }); // Subsequent queries will use persistence, if it was enabled successfully
Nhanh
let settings = FirestoreSettings() // Use memory-only cache settings.cacheSettings = MemoryCacheSettings(garbageCollectorSettings: MemoryLRUGCSettings()) // Use persistent disk cache, with 100 MB cache size settings.cacheSettings = PersistentCacheSettings(sizeBytes: 100 * 1024 * 1024 as NSNumber) // Any additional options // ... // Enable offline data persistence let db = Firestore.firestore() db.settings = settings
Mục tiêu-C
FIRFirestoreSettings *settings = [[FIRFirestoreSettings alloc] init]; // Use memory-only cache settings.cacheSettings = [[FIRMemoryCacheSettings alloc] initWithGarbageCollectorSettings:[[FIRMemoryLRUGCSettings alloc] init]]; // Use persistent disk cache (default behavior) // This example uses 100 MB. settings.cacheSettings = [[FIRPersistentCacheSettings alloc] initWithSizeBytes:@(100 * 1024 * 1024)]; // Any additional options // ... // Enable offline data persistence FIRFirestore *db = [FIRFirestore firestore]; db.settings = settings;
Kotlin+KTX
val settings = firestoreSettings { // Use memory cache setLocalCacheSettings(memoryCacheSettings {}) // Use persistent disk cache (default) setLocalCacheSettings(persistentCacheSettings {}) } db.firestoreSettings = settings
Java
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder(db.getFirestoreSettings()) // Use memory-only cache .setLocalCacheSettings(MemoryCacheSettings.newBuilder().build()) // Use persistent disk cache (default) .setLocalCacheSettings(PersistentCacheSettings.newBuilder() .build()) .build(); db.setFirestoreSettings(settings);
Dart
// Apple and Android db.settings = const Settings(persistenceEnabled: true); // Web await db .enablePersistence(const PersistenceSettings(synchronizeTabs: true));
Định cấu hình kích thước bộ đệm
Khi bật tính liên tục, Cloud Firestore sẽ lưu vào bộ đệm mọi tài liệu nhận được từ chương trình phụ trợ để truy cập ngoại tuyến. Cloud Firestore đặt ngưỡng mặc định cho kích thước bộ đệm. Sau khi vượt quá giá trị mặc định, Cloud Firestore định kỳ cố gắng dọn sạch các tài liệu cũ hơn, không sử dụng. Bạn có thể định cấu hình ngưỡng kích thước bộ nhớ đệm khác hoặc tắt hoàn toàn quá trình dọn dẹp:
Web modular API
import { initializeFirestore, CACHE_SIZE_UNLIMITED } from "firebase/firestore"; const firestoreDb = initializeFirestore(app, { cacheSizeBytes: CACHE_SIZE_UNLIMITED });
Web namespaced API
firebase.firestore().settings({ cacheSizeBytes: firebase.firestore.CACHE_SIZE_UNLIMITED });
Nhanh
// The default cache size threshold is 100 MB. Configure "cacheSizeBytes" // for a different threshold (minimum 1 MB) or set to "FirestoreCacheSizeUnlimited" // to disable clean-up. let settings = Firestore.firestore().settings // Set cache size to 100 MB settings.cacheSettings = PersistentCacheSettings(sizeBytes: 100 * 1024 * 1024 as NSNumber) Firestore.firestore().settings = settings
Mục tiêu-C
// The default cache size threshold is 100 MB. Configure "cacheSizeBytes" // for a different threshold (minimum 1 MB) or set to "kFIRFirestoreCacheSizeUnlimited" // to disable clean-up. FIRFirestoreSettings *settings = [FIRFirestore firestore].settings; // Set cache size to 100 MB settings.cacheSettings = [[FIRPersistentCacheSettings alloc] initWithSizeBytes:@(100 * 1024 * 1024)]; [FIRFirestore firestore].settings = settings;
Kotlin+KTX
// The default cache size threshold is 100 MB. Configure "setCacheSizeBytes" // for a different threshold (minimum 1 MB) or set to "CACHE_SIZE_UNLIMITED" // to disable clean-up. val settings = FirebaseFirestoreSettings.Builder() .setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED) .build() db.firestoreSettings = settings
Java
// The default cache size threshold is 100 MB. Configure "setCacheSizeBytes" // for a different threshold (minimum 1 MB) or set to "CACHE_SIZE_UNLIMITED" // to disable clean-up. FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder() .setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED) .build(); db.setFirestoreSettings(settings);
Dart
db.settings = const Settings( persistenceEnabled: true, cacheSizeBytes: Settings.CACHE_SIZE_UNLIMITED, );
Nghe dữ liệu ngoại tuyến
Khi thiết bị ngoại tuyến, nếu bạn đã bật tính năng duy trì ngoại tuyến, trình nghe của bạn sẽ nhận được các sự kiện nghe khi dữ liệu được lưu trong bộ nhớ đệm cục bộ thay đổi. Bạn có thể nghe tài liệu, bộ sưu tập và truy vấn.
Để kiểm tra xem bạn đang nhận dữ liệu từ máy chủ hay bộ đệm, hãy sử dụng thuộc tính fromCache
trên SnapshotMetadata
trong sự kiện chụp nhanh của bạn. Nếu fromCache
true
thì dữ liệu đến từ bộ nhớ đệm và có thể đã cũ hoặc không đầy đủ. Nếu fromCache
là false
thì dữ liệu đã đầy đủ và cập nhật với các bản cập nhật mới nhất trên máy chủ.
Theo mặc định, không có sự kiện nào được đưa ra nếu chỉ có SnapshotMetadata
thay đổi. Nếu bạn dựa vào các giá trị fromCache
, hãy chỉ định tùy chọn nghe includeMetadataChanges
khi bạn đính kèm trình xử lý nghe của mình.
Web modular API
import { collection, onSnapshot, where, query } from "firebase/firestore"; const q = query(collection(db, "cities"), where("state", "==", "CA")); onSnapshot(q, { includeMetadataChanges: true }, (snapshot) => { snapshot.docChanges().forEach((change) => { if (change.type === "added") { console.log("New city: ", change.doc.data()); } const source = snapshot.metadata.fromCache ? "local cache" : "server"; console.log("Data came from " + source); }); });
Web namespaced API
db.collection("cities").where("state", "==", "CA") .onSnapshot({ includeMetadataChanges: true }, (snapshot) => { snapshot.docChanges().forEach((change) => { if (change.type === "added") { console.log("New city: ", change.doc.data()); } var source = snapshot.metadata.fromCache ? "local cache" : "server"; console.log("Data came from " + source); }); });
Nhanh
// Listen to metadata updates to receive a server snapshot even if // the data is the same as the cached data. db.collection("cities").whereField("state", isEqualTo: "CA") .addSnapshotListener(includeMetadataChanges: true) { querySnapshot, error in guard let snapshot = querySnapshot else { print("Error retreiving snapshot: \(error!)") return } for diff in snapshot.documentChanges { if diff.type == .added { print("New city: \(diff.document.data())") } } let source = snapshot.metadata.isFromCache ? "local cache" : "server" print("Metadata: Data fetched from \(source)") }
Mục tiêu-C
// Listen to metadata updates to receive a server snapshot even if // the data is the same as the cached data. [[[db collectionWithPath:@"cities"] queryWhereField:@"state" isEqualTo:@"CA"] addSnapshotListenerWithIncludeMetadataChanges:YES listener:^(FIRQuerySnapshot *snapshot, NSError *error) { if (snapshot == nil) { NSLog(@"Error retreiving snapshot: %@", error); return; } for (FIRDocumentChange *diff in snapshot.documentChanges) { if (diff.type == FIRDocumentChangeTypeAdded) { NSLog(@"New city: %@", diff.document.data); } } NSString *source = snapshot.metadata.isFromCache ? @"local cache" : @"server"; NSLog(@"Metadata: Data fetched from %@", source); }];
Kotlin+KTX
db.collection("cities").whereEqualTo("state", "CA") .addSnapshotListener(MetadataChanges.INCLUDE) { querySnapshot, e -> if (e != null) { Log.w(TAG, "Listen error", e) return@addSnapshotListener } for (change in querySnapshot!!.documentChanges) { if (change.type == DocumentChange.Type.ADDED) { Log.d(TAG, "New city: ${change.document.data}") } val source = if (querySnapshot.metadata.isFromCache) { "local cache" } else { "server" } Log.d(TAG, "Data fetched from $source") } }
Java
db.collection("cities").whereEqualTo("state", "CA") .addSnapshotListener(MetadataChanges.INCLUDE, new EventListener<QuerySnapshot>() { @Override public void onEvent(@Nullable QuerySnapshot querySnapshot, @Nullable FirebaseFirestoreException e) { if (e != null) { Log.w(TAG, "Listen error", e); return; } for (DocumentChange change : querySnapshot.getDocumentChanges()) { if (change.getType() == Type.ADDED) { Log.d(TAG, "New city:" + change.getDocument().getData()); } String source = querySnapshot.getMetadata().isFromCache() ? "local cache" : "server"; Log.d(TAG, "Data fetched from " + source); } } });
Dart
db .collection("cities") .where("state", isEqualTo: "CA") .snapshots(includeMetadataChanges: true) .listen((querySnapshot) { for (var change in querySnapshot.docChanges) { if (change.type == DocumentChangeType.added) { final source = (querySnapshot.metadata.isFromCache) ? "local cache" : "server"; print("Data fetched from $source}"); } } });
Nhận dữ liệu ngoại tuyến
Nếu bạn nhận được tài liệu khi thiết bị ngoại tuyến, Cloud Firestore sẽ trả về dữ liệu từ bộ đệm.
Khi truy vấn một bộ sưu tập, kết quả trống sẽ được trả về nếu không có tài liệu nào được lưu trong bộ nhớ đệm. Thay vào đó, khi tìm nạp một tài liệu cụ thể, sẽ xảy ra lỗi.
Truy vấn dữ liệu ngoại tuyến
Truy vấn hoạt động với tính bền bỉ ngoại tuyến. Bạn có thể truy xuất kết quả của truy vấn bằng cách lấy trực tiếp hoặc bằng cách nghe, như được mô tả trong các phần trước. Bạn cũng có thể tạo các truy vấn mới trên dữ liệu được lưu trữ cục bộ trong khi thiết bị ngoại tuyến, nhưng ban đầu các truy vấn sẽ chỉ chạy đối với các tài liệu được lưu trong bộ nhớ đệm.
Định cấu hình chỉ mục truy vấn ngoại tuyến
Theo mặc định, SDK Firestore quét tất cả tài liệu trong bộ sưu tập trong bộ đệm cục bộ khi thực hiện truy vấn ngoại tuyến. Với hành vi mặc định này, hiệu suất truy vấn ngoại tuyến có thể bị ảnh hưởng khi người dùng ngoại tuyến trong thời gian dài.
Khi bật bộ nhớ đệm liên tục, bạn có thể cải thiện hiệu suất của truy vấn ngoại tuyến bằng cách cho phép SDK tự động tạo chỉ mục truy vấn cục bộ.
Lập chỉ mục tự động bị tắt theo mặc định. Ứng dụng của bạn phải bật tính năng lập chỉ mục tự động mỗi khi khởi động. Kiểm soát xem có bật tính năng lập chỉ mục tự động hay không như hiển thị bên dưới.
Nhanh
if let indexManager = Firestore.firestore().persistentCacheIndexManager { // Indexing is disabled by default indexManager.enableIndexAutoCreation() } else { print("indexManager is nil") }
Mục tiêu-C
PersistentCacheIndexManager *indexManager = [FIRFirestore firestore].persistentCacheIndexManager; if (indexManager) { // Indexing is disabled by default [indexManager enableIndexAutoCreation]; }
Kotlin+KTX
// return type: PersistentCacheManager? Firebase.firestore.persistentCacheIndexManager?.apply { // Indexing is disabled by default enableIndexAutoCreation() } ?: println("indexManager is null")
Java
// return type: @Nullable PersistentCacheIndexManager PersistentCacheIndexManager indexManager = FirebaseFirestore.getInstance().getPersistentCacheIndexManager(); if (indexManager != null) { // Indexing is disabled by default indexManager.enableIndexAutoCreation(); } // If not check indexManager != null, IDE shows warning: Method invocation 'enableIndexAutoCreation' may produce 'NullPointerException' FirebaseFirestore.getInstance().getPersistentCacheIndexManager().enableIndexAutoCreation();
Sau khi bật tính năng lập chỉ mục tự động, SDK sẽ đánh giá bộ sưu tập nào có số lượng lớn tài liệu được lưu vào bộ nhớ đệm và tối ưu hóa hiệu suất của các truy vấn cục bộ.
SDK cung cấp phương pháp xóa chỉ mục truy vấn.
Vô hiệu hóa và kích hoạt truy cập mạng
Bạn có thể sử dụng phương pháp bên dưới để vô hiệu hóa quyền truy cập mạng cho ứng dụng khách Cloud Firestore của mình. Khi quyền truy cập mạng bị vô hiệu hóa, tất cả trình xử lý ảnh chụp nhanh và yêu cầu tài liệu đều truy xuất kết quả từ bộ nhớ đệm. Hoạt động ghi được xếp hàng đợi cho đến khi quyền truy cập mạng được kích hoạt lại.
Web modular API
import { disableNetwork } from "firebase/firestore"; await disableNetwork(db); console.log("Network disabled!"); // Do offline actions // ...
Web namespaced API
firebase.firestore().disableNetwork() .then(() => { // Do offline actions // ... });
Nhanh
Firestore.firestore().disableNetwork { (error) in // Do offline things // ... }
Mục tiêu-C
[[FIRFirestore firestore] disableNetworkWithCompletion:^(NSError *_Nullable error) { // Do offline actions // ... }];
Kotlin+KTX
db.disableNetwork().addOnCompleteListener { // Do offline things // ... }
Java
db.disableNetwork() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // Do offline things // ... } });
Dart
db.disableNetwork().then((_) { // Do offline things });
Sử dụng phương pháp sau để kích hoạt lại quyền truy cập mạng:
Web modular API
import { enableNetwork } from "firebase/firestore"; await enableNetwork(db); // Do online actions // ...
Web namespaced API
firebase.firestore().enableNetwork() .then(() => { // Do online actions // ... });
Nhanh
Firestore.firestore().enableNetwork { (error) in // Do online things // ... }
Mục tiêu-C
[[FIRFirestore firestore] enableNetworkWithCompletion:^(NSError *_Nullable error) { // Do online actions // ... }];
Kotlin+KTX
db.enableNetwork().addOnCompleteListener { // Do online things // ... }
Java
db.enableNetwork() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { // Do online things // ... } });
Dart
db.enableNetwork().then((_) { // Back online });