diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java index efe017ff..9dc57fc6 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabase.java @@ -13,7 +13,6 @@ import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.google.firebase.FirebaseApp; -import com.google.firebase.database.ChildEventListener; import com.google.firebase.database.MutableData; import com.google.firebase.database.OnDisconnect; import com.google.firebase.database.ServerValue; @@ -22,7 +21,6 @@ import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.DatabaseReference; -import com.google.firebase.database.ValueEventListener; import java.util.HashMap; import java.util.List; @@ -33,40 +31,13 @@ import io.invertase.firebase.Utils; public class RNFirebaseDatabase extends ReactContextBaseJavaModule { private static final String TAG = "RNFirebaseDatabase"; - private HashMap childEventListeners; - private HashMap valueEventListeners; - private HashMap references = new HashMap(); + private HashMap references = new HashMap<>(); private SparseArray transactionHandlers = new SparseArray<>(); RNFirebaseDatabase(ReactApplicationContext reactContext) { super(reactContext); - childEventListeners = new HashMap(); - valueEventListeners = new HashMap(); } - Boolean hasValueEventListener(String queryKey) { - return valueEventListeners.containsKey(queryKey); - } - - Boolean hasChildEventListener(String queryKey) { - return childEventListeners.containsKey(queryKey); - } - - void addValueEventListener(String queryKey, ValueEventListener listener) { - valueEventListeners.put(queryKey, listener); - } - - void addChildEventListener(String queryKey, ChildEventListener listener) { - childEventListeners.put(queryKey, listener); - } - - void removeValueEventListener(String queryKey) { - valueEventListeners.remove(queryKey); - } - - void removeChildEventListener(String queryKey) { - childEventListeners.remove(queryKey); - } /* * REACT NATIVE METHODS @@ -427,17 +398,29 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { */ @ReactMethod public void on(String appName, ReadableMap props) { - getInternalReferenceForApp(appName, props).on( - this, - props.getString("eventType"), - props.getMap("registration") - ); + getInternalReferenceForApp(appName, props) + .on( + this, + props.getString("eventType"), + props.getMap("registration") + ); } - + /** + * Removes the specified event registration key. + * If the ref no longer has any listeners the the ref is removed. + * + * @param key + * @param eventRegistrationKey + */ @ReactMethod - public void off(String appName, ReadableMap args) { + public void off(String key, String eventRegistrationKey) { + RNFirebaseDatabaseReference nativeRef = references.get(key); + nativeRef.removeEventListener(eventRegistrationKey); + if (!nativeRef.hasListeners()) { + references.remove(key); + } } /* @@ -463,27 +446,6 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { } } - /** - * React Method - returns this module name - * - * @return - */ - @Override - public String getName() { - return "RNFirebaseDatabase"; - } - - /** - * React Native constants for RNFirebaseDatabase - * - * @return - */ - @Override - public Map getConstants() { - final Map constants = new HashMap<>(); - constants.put("serverValueTimestamp", ServerValue.TIMESTAMP); - return constants; - } /** * Get a database instance for a specific firebase app instance @@ -533,6 +495,8 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { } /** + * TODO + * * @param appName * @param props * @return @@ -657,4 +621,26 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule { errorMap.putString("message", message); return errorMap; } + + /** + * React Method - returns this module name + * + * @return + */ + @Override + public String getName() { + return "RNFirebaseDatabase"; + } + + /** + * React Native constants for RNFirebaseDatabase + * + * @return + */ + @Override + public Map getConstants() { + final Map constants = new HashMap<>(); + constants.put("serverValueTimestamp", ServerValue.TIMESTAMP); + return constants; + } } diff --git a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java index 6a50f716..e45eea25 100644 --- a/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java +++ b/android/src/main/java/io/invertase/firebase/database/RNFirebaseDatabaseReference.java @@ -1,5 +1,6 @@ package io.invertase.firebase.database; +import java.util.HashMap; import java.util.Map; import java.util.List; @@ -23,20 +24,21 @@ import com.google.firebase.database.ValueEventListener; import io.invertase.firebase.Utils; class RNFirebaseDatabaseReference { - private static final String TAG = "RNFirebaseDBReference"; - private String key; private Query query; - private String path; private String appName; private ReactContext reactContext; - + private static final String TAG = "RNFirebaseDBReference"; + private HashMap childEventListeners; + private HashMap valueEventListeners; Query getQuery() { return query; } /** + * TODO + * * @param context * @param app * @param refKey @@ -46,9 +48,67 @@ class RNFirebaseDatabaseReference { RNFirebaseDatabaseReference(ReactContext context, String app, String refKey, String refPath, ReadableArray modifiersArray) { key = refKey; appName = app; - path = refPath; reactContext = context; - query = buildDatabaseQueryAtPathAndModifiers(path, modifiersArray); + childEventListeners = new HashMap(); + valueEventListeners = new HashMap(); + query = buildDatabaseQueryAtPathAndModifiers(refPath, modifiersArray); + } + + /** + * Returns true/false whether this internal ref has a specific listener by eventRegistrationKey. + * + * @param eventRegistrationKey + * @return + */ + private Boolean hasEventListener(String eventRegistrationKey) { + return valueEventListeners.containsKey(eventRegistrationKey) || childEventListeners.containsKey(eventRegistrationKey); + } + + /** + * Returns true/false whether this internal ref has any child or value listeners. + * + * @return + */ + Boolean hasListeners() { + return valueEventListeners.size() > 0 || childEventListeners.size() > 0; + } + + /** + * TODO + * + * @param eventRegistrationKey + */ + void removeEventListener(String eventRegistrationKey) { + if (valueEventListeners.containsKey(eventRegistrationKey)) { + query.removeEventListener(valueEventListeners.get(eventRegistrationKey)); + valueEventListeners.remove(eventRegistrationKey); + } + + if (childEventListeners.containsKey(eventRegistrationKey)) { + query.removeEventListener(childEventListeners.get(eventRegistrationKey)); + childEventListeners.remove(eventRegistrationKey); + } + } + + /** + * TODO + * + * @param eventRegistrationKey + * @param listener + */ + private void addEventListener(String eventRegistrationKey, ValueEventListener listener) { + valueEventListeners.put(eventRegistrationKey, listener); + } + + + /** + * TODO + * + * @param eventRegistrationKey + * @param listener + */ + private void addEventListener(String eventRegistrationKey, ChildEventListener listener) { + childEventListeners.put(eventRegistrationKey, listener); } /** @@ -71,7 +131,6 @@ class RNFirebaseDatabaseReference { }; query.addListenerForSingleValueEvent(onceValueEventListener); - Log.d(TAG, "Added OnceValueEventListener for key: " + key); } @@ -160,6 +219,8 @@ class RNFirebaseDatabaseReference { /** + * TODO + * * @param registration * @param eventType * @param database @@ -168,7 +229,7 @@ class RNFirebaseDatabaseReference { final String eventRegistrationKey = registration.getString("eventRegistrationKey"); final String registrationCancellationKey = registration.getString("registrationCancellationKey"); - if (!database.hasChildEventListener(eventRegistrationKey)) { + if (!hasEventListener(eventRegistrationKey)) { ChildEventListener childEventListener = new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) { @@ -200,25 +261,26 @@ class RNFirebaseDatabaseReference { @Override public void onCancelled(DatabaseError error) { - query.removeEventListener(this); - database.removeChildEventListener(eventRegistrationKey); + removeEventListener(eventRegistrationKey); handleDatabaseError(registration, error); } }; - database.addChildEventListener(eventRegistrationKey, childEventListener); + addEventListener(eventRegistrationKey, childEventListener); query.addChildEventListener(childEventListener); } } /** + * TODO + * * @param registration */ private void addValueEventListener(final ReadableMap registration, final RNFirebaseDatabase database) { final String eventRegistrationKey = registration.getString("eventRegistrationKey"); final String registrationCancellationKey = registration.getString("registrationCancellationKey"); - if (!database.hasValueEventListener(eventRegistrationKey)) { + if (!hasEventListener(eventRegistrationKey)) { ValueEventListener valueEventListener = new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { @@ -227,13 +289,12 @@ class RNFirebaseDatabaseReference { @Override public void onCancelled(DatabaseError error) { - query.removeEventListener(this); - database.removeValueEventListener(eventRegistrationKey); + removeEventListener(eventRegistrationKey); handleDatabaseError(registration, error); } }; - database.addValueEventListener(eventRegistrationKey, valueEventListener); + addEventListener(eventRegistrationKey, valueEventListener); query.addValueEventListener(valueEventListener); } } @@ -271,44 +332,6 @@ class RNFirebaseDatabaseReference { Utils.sendEvent(reactContext, "database_sync_event", event); } - - // todo cleanup below - -// void removeEventListener(int listenerId, String eventName) { -// if ("value".equals(eventName)) { -// removeValueEventListener(listenerId); -// } else { -// removeChildEventListener(listenerId); -// } -// } - -// boolean hasListeners() { -// return childEventListeners.size() > 0 || valueEventListeners.size() > 0; -// } -// -// public void cleanup() { -// Log.d(TAG, "cleaning up database reference " + this); -// this.removeChildEventListener(null); -// this.removeValueEventListener(null); -// } - -// private void removeChildEventListener(Integer listenerId) { -// ChildEventListener listener = childEventListeners.get(listenerId); -// if (listener != null) { -// query.removeEventListener(listener); -// childEventListeners.remove(listenerId); -// } -// } -// -// private void removeValueEventListener(Integer listenerId) { -// ValueEventListener listener = valueEventListeners.get(listenerId); -// if (listener != null) { -// query.removeEventListener(listener); -// valueEventListeners.delete(listenerId); -// } -// } - - private Query buildDatabaseQueryAtPathAndModifiers(String path, ReadableArray modifiers) { FirebaseDatabase firebaseDatabase = RNFirebaseDatabase.getDatabaseForApp(appName);