From ba8ad591e5940d576c5c50aa059a66093269dbcd Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Wed, 19 Aug 2026 18:30:41 -0700 Subject: [PATCH] fix: preserve keepSynced state across Query.get Fixes #8433 --- firebase-database/CHANGELOG.md | 2 ++ .../google/firebase/database/QueryTest.java | 26 +++++++++++++++++++ .../google/firebase/database/core/Repo.java | 11 +++++--- .../firebase/database/core/SyncTree.java | 4 ++- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/firebase-database/CHANGELOG.md b/firebase-database/CHANGELOG.md index 616f9074e3b..5fc4415f620 100644 --- a/firebase-database/CHANGELOG.md +++ b/firebase-database/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +- [fixed] Fixed a crash when calling `keepSynced(true)` and `get()` on the same query. + # 22.0.1 - [changed] Bumped internal dependencies. diff --git a/firebase-database/src/androidTest/java/com/google/firebase/database/QueryTest.java b/firebase-database/src/androidTest/java/com/google/firebase/database/QueryTest.java index c56169b1c5c..0f2aa4bec3a 100644 --- a/firebase-database/src/androidTest/java/com/google/firebase/database/QueryTest.java +++ b/firebase-database/src/androidTest/java/com/google/firebase/database/QueryTest.java @@ -5048,6 +5048,32 @@ public void testGetSendsServerGetForNodeWithNoListenerWhenOnline() assertEquals(42L, await(node.get()).getValue()); } + @Test + public void testGetPreservesKeepSyncedState() + throws DatabaseException, InterruptedException, ExecutionException { + FirebaseDatabase writerDb = getNewDatabase(); + FirebaseDatabase readerDb = getNewDatabase(); + readerDb.setPersistenceEnabled(false); + DatabaseReference writer = writerDb.getReference().push(); + DatabaseReference reader = translateReference(writer, readerDb); + + await(writer.setValue(42L)); + + try { + reader.keepSynced(true); + assertEquals(42L, await(reader.get()).getValue()); + + reader.keepSynced(true); + assertEquals(42L, await(reader.get()).getValue()); + + DatabaseReference equivalentReader = translateReference(writer, readerDb); + equivalentReader.keepSynced(true); + assertEquals(42L, await(equivalentReader.get()).getValue()); + } finally { + reader.keepSynced(false); + } + } + @Test public void testGetProbesInMemoryCacheForActiveListenerWhenOffline() throws DatabaseException, diff --git a/firebase-database/src/main/java/com/google/firebase/database/core/Repo.java b/firebase-database/src/main/java/com/google/firebase/database/core/Repo.java index d480b1a04ce..da3cfaf782b 100644 --- a/firebase-database/src/main/java/com/google/firebase/database/core/Repo.java +++ b/firebase-database/src/main/java/com/google/firebase/database/core/Repo.java @@ -558,7 +558,8 @@ public void run() { QuerySpec spec = query.getSpec(); // EventRegistrations require a listener to be attached, so a dummy // ValueEventListener was created. - keepSynced(spec, /* keep= */ true, /* skipDedup= */ true); + boolean addedKeepSyncedRegistration = + keepSynced(spec, /* keep= */ true, /* skipDedup= */ true); List events; if (spec.loadsAllData()) { events = serverSyncTree.applyServerOverwrite(spec.getPath(), serverNode); @@ -576,7 +577,9 @@ public void run() { InternalHelpers.createDataSnapshot( query.getRef(), IndexedNode.from(serverNode, query.getSpec().getIndex()))); - keepSynced(spec, /* keep= */ false, /* skipDedup= */ true); + if (addedKeepSyncedRegistration) { + keepSynced(spec, /* keep= */ false, /* skipDedup= */ true); + } } }); } @@ -767,9 +770,9 @@ public void keepSynced(QuerySpec query, boolean keep) { keepSynced(query, keep, /* skipDedup= */ false); } - public void keepSynced(QuerySpec query, boolean keep, final boolean skipDedup) { + public boolean keepSynced(QuerySpec query, boolean keep, final boolean skipDedup) { hardAssert(query.getPath().isEmpty() || !query.getPath().getFront().equals(Constants.DOT_INFO)); - serverSyncTree.keepSynced(query, keep, skipDedup); + return serverSyncTree.keepSynced(query, keep, skipDedup); } PersistentConnection getConnection() { diff --git a/firebase-database/src/main/java/com/google/firebase/database/core/SyncTree.java b/firebase-database/src/main/java/com/google/firebase/database/core/SyncTree.java index 95ace631abf..29627f51f56 100644 --- a/firebase-database/src/main/java/com/google/firebase/database/core/SyncTree.java +++ b/firebase-database/src/main/java/com/google/firebase/database/core/SyncTree.java @@ -851,16 +851,18 @@ public void keepSynced(final QuerySpec query, final boolean keep) { keepSynced(query, keep, false); } - public void keepSynced(final QuerySpec query, final boolean keep, final boolean skipDedup) { + public boolean keepSynced(final QuerySpec query, final boolean keep, final boolean skipDedup) { if (keep && !keepSyncedQueries.contains(query)) { // TODO[persistence]: Find better / more efficient way to do keep-synced listeners. addEventRegistration( new KeepSyncedEventRegistration(query), /* skipListenerSetup= */ skipDedup); keepSyncedQueries.add(query); + return true; } else if (!keep && keepSyncedQueries.contains(query)) { removeEventRegistration(new KeepSyncedEventRegistration(query), skipDedup); keepSyncedQueries.remove(query); } + return false; } /**