22
22
import com .google .auto .value .AutoValue ;
23
23
import com .google .firebase .firestore .ListenerRegistration ;
24
24
import com .google .firebase .firestore .util .Executors ;
25
- import java .util .HashMap ;
26
- import java .util .Map ;
25
+ import java .util .concurrent . CopyOnWriteArrayList ;
26
+ import java .util .concurrent . atomic . AtomicReference ;
27
27
28
28
/**
29
29
* Manages "testing hooks", hooks into the internals of the SDK to verify internal state and events
@@ -36,8 +36,10 @@ final class TestingHooks {
36
36
37
37
private static final TestingHooks instance = new TestingHooks ();
38
38
39
- private final Map <Object , ExistenceFilterMismatchListener > existenceFilterMismatchListeners =
40
- new HashMap <>();
39
+ // Use CopyOnWriteArrayList to store the listeners so that we don't need to worry about
40
+ // synchronizing adds, removes, and traversals.
41
+ private final CopyOnWriteArrayList <AtomicReference <ExistenceFilterMismatchListener >>
42
+ existenceFilterMismatchListeners = new CopyOnWriteArrayList <>();
41
43
42
44
private TestingHooks () {}
43
45
@@ -48,16 +50,21 @@ static TestingHooks getInstance() {
48
50
}
49
51
50
52
/**
51
- * Notifies all registered {@link ExistenceFilterMismatchListener}` listeners registered via
52
- * {@link #addExistenceFilterMismatchListener}.
53
+ * Asynchronously notifies all registered {@link ExistenceFilterMismatchListener}` listeners
54
+ * registered via {@link #addExistenceFilterMismatchListener}.
53
55
*
54
56
* @param info Information about the existence filter mismatch to deliver to the listeners.
55
57
*/
56
58
void notifyOnExistenceFilterMismatch (@ NonNull ExistenceFilterMismatchInfo info ) {
57
- synchronized (existenceFilterMismatchListeners ) {
58
- for (ExistenceFilterMismatchListener listener : existenceFilterMismatchListeners .values ()) {
59
- Executors .BACKGROUND_EXECUTOR .execute (() -> listener .onExistenceFilterMismatch (info ));
60
- }
59
+ for (AtomicReference <ExistenceFilterMismatchListener > listenerRef :
60
+ existenceFilterMismatchListeners ) {
61
+ Executors .BACKGROUND_EXECUTOR .execute (
62
+ () -> {
63
+ ExistenceFilterMismatchListener listener = listenerRef .get ();
64
+ if (listener != null ) {
65
+ listener .onExistenceFilterMismatch (info );
66
+ }
67
+ });
61
68
}
62
69
}
63
70
@@ -83,15 +90,12 @@ ListenerRegistration addExistenceFilterMismatchListener(
83
90
@ NonNull ExistenceFilterMismatchListener listener ) {
84
91
checkNotNull (listener , "a null listener is not allowed" );
85
92
86
- Object listenerId = new Object ();
87
- synchronized (existenceFilterMismatchListeners ) {
88
- existenceFilterMismatchListeners .put (listenerId , listener );
89
- }
93
+ AtomicReference <ExistenceFilterMismatchListener > listenerRef = new AtomicReference <>(listener );
94
+ existenceFilterMismatchListeners .add (listenerRef );
90
95
91
96
return () -> {
92
- synchronized (existenceFilterMismatchListeners ) {
93
- existenceFilterMismatchListeners .remove (listenerId );
94
- }
97
+ listenerRef .set (null );
98
+ existenceFilterMismatchListeners .remove (listenerRef );
95
99
};
96
100
}
97
101
0 commit comments