[database][wip] on/off logic refactor - heavily still wip so things still to change

This commit is contained in:
Salakar
2017-08-14 11:05:49 +01:00
parent 0675aa076d
commit f1709970e9
13 changed files with 573 additions and 458 deletions
@@ -81,10 +81,9 @@ public class Utils {
* @param path
* @param dataSnapshot
* @param refId
* @param listenerId
* @return
*/
public static WritableMap snapshotToMap(String name, String path, DataSnapshot dataSnapshot, @Nullable String previousChildName, int refId, int listenerId) {
public static WritableMap snapshotToMap(String name, String path, DataSnapshot dataSnapshot, @Nullable String previousChildName, int refId) {
WritableMap snapshot = Arguments.createMap();
WritableMap eventMap = Arguments.createMap();
@@ -111,7 +110,6 @@ public class Utils {
eventMap.putString("path", path);
eventMap.putMap("snapshot", snapshot);
eventMap.putString("eventName", name);
eventMap.putInt("listenerId", listenerId);
eventMap.putString("previousChildName", previousChildName);
return eventMap;
@@ -13,6 +13,7 @@ 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;
@@ -21,6 +22,7 @@ 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;
@@ -31,11 +33,39 @@ import io.invertase.firebase.Utils;
public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
private static final String TAG = "RNFirebaseDatabase";
private HashMap<String, ChildEventListener> childEventListeners;
private HashMap<String, ValueEventListener> valueEventListeners;
private SparseArray<RNFirebaseDatabaseReference> references = new SparseArray<>();
private SparseArray<RNFirebaseTransactionHandler> transactionHandlers = new SparseArray<>();
RNFirebaseDatabase(ReactApplicationContext reactContext) {
super(reactContext);
childEventListeners = new HashMap<String, ChildEventListener>();
valueEventListeners = new HashMap<String, ValueEventListener>();
}
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);
}
/*
@@ -394,17 +424,20 @@ public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
/**
* Subscribe to real time events for the specified database path + modifiers
*
* @param appName
* @param refId
* @param path
* @param modifiers
* @param eventName
* @param promise
* @param appName String
* @param args ReadableMap
*/
@ReactMethod
public void on(String appName, int refId, String path, ReadableArray modifiers, String eventName, Promise promise) {
getInternalReferenceForApp(appName, refId, path, modifiers, true).on(eventName);
public void on(String appName, ReadableMap args) {
RNFirebaseDatabaseReference ref = getInternalReferenceForApp(
appName,
args.getInt("id"),
args.getString("path"),
args.getArray("modifiers"),
true
);
ref.on(this, args.getString("eventType"), args.getString("eventQueryKey"));
}
/*
@@ -1,5 +1,6 @@
package io.invertase.firebase.database;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
@@ -9,6 +10,7 @@ import android.util.SparseArray;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
@@ -30,8 +32,7 @@ public class RNFirebaseDatabaseReference {
private String path;
private String appName;
private ReactContext reactContext;
private SparseArray<ChildEventListener> childEventListeners;
private SparseArray<ValueEventListener> valueEventListeners;
Query getQuery() {
return query;
@@ -49,8 +50,6 @@ public class RNFirebaseDatabaseReference {
appName = app;
path = refPath;
reactContext = context;
childEventListeners = new SparseArray<ChildEventListener>();
valueEventListeners = new SparseArray<ValueEventListener>();
query = buildDatabaseQueryAtPathAndModifiers(path, modifiersArray);
}
@@ -63,7 +62,7 @@ public class RNFirebaseDatabaseReference {
ValueEventListener onceValueEventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
WritableMap data = Utils.snapshotToMap("value", path, dataSnapshot, null, refId, 0);
WritableMap data = Utils.snapshotToMap("value", path, dataSnapshot, null, refId);
promise.resolve(data);
}
@@ -90,7 +89,7 @@ public class RNFirebaseDatabaseReference {
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
if ("child_added".equals(eventName)) {
query.removeEventListener(this);
WritableMap data = Utils.snapshotToMap("child_added", path, dataSnapshot, previousChildName, refId, 0);
WritableMap data = Utils.snapshotToMap("child_added", path, dataSnapshot, previousChildName, refId);
promise.resolve(data);
}
}
@@ -99,7 +98,7 @@ public class RNFirebaseDatabaseReference {
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
if ("child_changed".equals(eventName)) {
query.removeEventListener(this);
WritableMap data = Utils.snapshotToMap("child_changed", path, dataSnapshot, previousChildName, refId, 0);
WritableMap data = Utils.snapshotToMap("child_changed", path, dataSnapshot, previousChildName, refId);
promise.resolve(data);
}
}
@@ -108,7 +107,7 @@ public class RNFirebaseDatabaseReference {
public void onChildRemoved(DataSnapshot dataSnapshot) {
if ("child_removed".equals(eventName)) {
query.removeEventListener(this);
WritableMap data = Utils.snapshotToMap("child_removed", path, dataSnapshot, null, refId, 0);
WritableMap data = Utils.snapshotToMap("child_removed", path, dataSnapshot, null, refId);
promise.resolve(data);
}
}
@@ -117,7 +116,7 @@ public class RNFirebaseDatabaseReference {
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
if ("child_moved".equals(eventName)) {
query.removeEventListener(this);
WritableMap data = Utils.snapshotToMap("child_moved", path, dataSnapshot, previousChildName, refId, 0);
WritableMap data = Utils.snapshotToMap("child_moved", path, dataSnapshot, previousChildName, refId);
promise.resolve(data);
}
}
@@ -135,14 +134,20 @@ public class RNFirebaseDatabaseReference {
/**
* Handles a React Native JS 'on' request and initializes listeners.
*
* @param eventName
*/
void on(String eventName) {
void on(RNFirebaseDatabase database, String eventName, String queryKey) {
if (eventName.equals("value")) {
addValueEventListener(queryKey, database);
} else {
addChildEventListener(queryKey, database, eventName);
}
}
/**
* Handles a React Native JS 'once' request.
*
* @param eventName
* @param promise
*/
@@ -155,136 +160,153 @@ public class RNFirebaseDatabaseReference {
}
// todo cleanup all below
void addChildEventListener(final int listenerId, final String eventName) {
if (childEventListeners.get(listenerId) != null) {
/**
* @param queryKey
* @param eventName
*/
private void addChildEventListener(final String queryKey, final RNFirebaseDatabase database, final String eventName) {
if (!database.hasChildEventListener(queryKey)) {
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
if ("child_added".equals(eventName)) {
handleDatabaseEvent("child_added", listenerId, dataSnapshot, previousChildName);
handleDatabaseEvent("child_added", queryKey, dataSnapshot, previousChildName);
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
if ("child_changed".equals(eventName)) {
handleDatabaseEvent("child_changed", listenerId, dataSnapshot, previousChildName);
handleDatabaseEvent("child_changed", queryKey, dataSnapshot, previousChildName);
}
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
if ("child_removed".equals(eventName)) {
handleDatabaseEvent("child_removed", listenerId, dataSnapshot, null);
handleDatabaseEvent("child_removed", queryKey, dataSnapshot, null);
}
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
if ("child_moved".equals(eventName)) {
handleDatabaseEvent("child_moved", listenerId, dataSnapshot, previousChildName);
handleDatabaseEvent("child_moved", queryKey, dataSnapshot, previousChildName);
}
}
@Override
public void onCancelled(DatabaseError error) {
removeChildEventListener(listenerId);
handleDatabaseError(listenerId, error);
query.removeEventListener(this);
database.removeChildEventListener(queryKey);
handleDatabaseError(queryKey, error);
}
};
childEventListeners.put(listenerId, childEventListener);
database.addChildEventListener(queryKey, childEventListener);
query.addChildEventListener(childEventListener);
Log.d(TAG, "Added ChildEventListener for refId: " + refId + " listenerId: " + listenerId);
} else {
Log.d(TAG, "ChildEventListener for refId: " + refId + " listenerId: " + listenerId + " already exists");
}
}
void addValueEventListener(final int listenerId) {
if (valueEventListeners.get(listenerId) != null) {
/**
* @param queryKey
*/
private void addValueEventListener(final String queryKey, final RNFirebaseDatabase database) {
if (!database.hasValueEventListener(queryKey)) {
ValueEventListener valueEventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
handleDatabaseEvent("value", listenerId, dataSnapshot, null);
handleDatabaseEvent("value", queryKey, dataSnapshot, null);
}
@Override
public void onCancelled(DatabaseError error) {
removeValueEventListener(listenerId);
handleDatabaseError(listenerId, error);
query.removeEventListener(this);
database.removeValueEventListener(queryKey);
handleDatabaseError(queryKey, error);
}
};
valueEventListeners.put(listenerId, valueEventListener);
database.addValueEventListener(queryKey, valueEventListener);
query.addValueEventListener(valueEventListener);
Log.d(TAG, "Added ValueEventListener for refId: " + refId + " listenerId: " + listenerId);
} else {
Log.d(TAG, "ValueEventListener for refId: " + refId + " listenerId: " + listenerId + " already exists");
}
}
void removeEventListener(int listenerId, String eventName) {
if ("value".equals(eventName)) {
this.removeValueEventListener(listenerId);
} else {
this.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.delete(listenerId);
}
}
private void removeValueEventListener(Integer listenerId) {
ValueEventListener listener = valueEventListeners.get(listenerId);
if (listener != null) {
query.removeEventListener(listener);
valueEventListeners.delete(listenerId);
}
}
private void handleDatabaseEvent(final String name, final Integer listenerId, final DataSnapshot dataSnapshot, @Nullable String previousChildName) {
WritableMap data = Utils.snapshotToMap(name, path, dataSnapshot, previousChildName, refId, listenerId);
/**
* @param name
* @param dataSnapshot
* @param previousChildName
*/
private void handleDatabaseEvent(final String name, String queryKey, final DataSnapshot dataSnapshot, @Nullable String previousChildName) {
WritableMap evt = Arguments.createMap();
evt.putString("eventName", name);
evt.putMap("body", data);
WritableMap data = Utils.snapshotToMap(name, path, dataSnapshot, previousChildName, refId);
Utils.sendEvent(reactContext, "database_event", evt);
evt.putMap("body", data);
evt.putInt("refId", refId);
evt.putString("eventName", name);
evt.putString("appName", appName);
evt.putString("queryKey", queryKey);
Utils.sendEvent(reactContext, "database_on_event", evt);
}
private void handleDatabaseError(final Integer listenerId, final DatabaseError error) {
/**
* Handles a database listener cancellation error.
*
* @param error
*/
private void handleDatabaseError(String queryKey, final DatabaseError error) {
WritableMap errMap = Arguments.createMap();
errMap.putInt("refId", refId);
if (listenerId != null) {
errMap.putInt("listenerId", listenerId);
}
errMap.putString("path", path);
errMap.putString("appName", appName);
errMap.putString("queryKey", queryKey);
errMap.putInt("code", error.getCode());
errMap.putString("details", error.getDetails());
errMap.putString("message", error.getMessage());
Utils.sendEvent(reactContext, "database_error", errMap);
Utils.sendEvent(reactContext, "database_cancel_event", errMap);
}
// 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);