Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[android][database] Remove all db references and listeners onCatalystInstanceDestroy #1535

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,33 @@
import com.google.firebase.database.Transaction;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import io.invertase.firebase.ErrorUtils;
import io.invertase.firebase.Utils;

@SuppressWarnings("JavaDoc")
public class RNFirebaseDatabase extends ReactContextBaseJavaModule {
private static final String TAG = "RNFirebaseDatabase";
private static boolean enableLogging = false;
private static RNFirebaseDatabase instance = null;
private static HashMap<String, Boolean> loggingLevelSet = new HashMap<>();
private HashMap<String, RNFirebaseDatabaseReference> references = new HashMap<>();
private SparseArray<RNFirebaseTransactionHandler> transactionHandlers = new SparseArray<>();
private static HashMap<String, RNFirebaseDatabaseReference> references = new HashMap<>();
private static SparseArray<RNFirebaseTransactionHandler> transactionHandlers = new SparseArray<>();

RNFirebaseDatabase(ReactApplicationContext reactContext) {
super(reactContext);
}
protected ReactApplicationContext reactContext = null;

RNFirebaseDatabase(ReactApplicationContext _reactContext) {
super(_reactContext);
instance = this;
reactContext = _reactContext;
}

/*
* REACT NATIVE METHODS
*/
public static RNFirebaseDatabase getInstance() {
return instance;
}

/**
* Resolve null or reject with a js like error if databaseError exists
Expand Down Expand Up @@ -73,7 +79,7 @@ static void handlePromise(Promise promise, DatabaseError databaseError) {
* @param dbURL
* @return
*/
public static FirebaseDatabase getDatabaseForApp(String appName, String dbURL) {
static FirebaseDatabase getDatabaseForApp(String appName, String dbURL) {
FirebaseDatabase firebaseDatabase;
if (dbURL != null && dbURL.length() > 0) {
if (appName != null && appName.length() > 0) {
Expand Down Expand Up @@ -251,6 +257,19 @@ static WritableMap getJSError(DatabaseError nativeError) {
return errorMap;
}

@Override
public void onCatalystInstanceDestroy() {
instance = null;
reactContext = null;
Iterator refIterator = references.entrySet().iterator();
while (refIterator.hasNext()) {
Map.Entry pair = (Map.Entry) refIterator.next();
RNFirebaseDatabaseReference nativeRef = (RNFirebaseDatabaseReference) pair.getValue();
nativeRef.removeAllEventListeners();
refIterator.remove(); // avoids a ConcurrentModificationException
}
}

/**
* @param appName
*/
Expand Down Expand Up @@ -785,7 +804,6 @@ private RNFirebaseDatabaseReference getInternalReferenceForApp(
ReadableArray modifiers
) {
return new RNFirebaseDatabaseReference(
getReactApplicationContext(),
appName,
dbURL,
key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
Expand All @@ -21,33 +20,32 @@

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import io.invertase.firebase.Utils;

@SuppressWarnings("JavaDoc")
class RNFirebaseDatabaseReference {
private static final String TAG = "RNFirebaseDBReference";
private String key;
private Query query;
private String appName;
private String dbURL;
private ReactContext reactContext;
private String appName;
private HashMap<String, ChildEventListener> childEventListeners = new HashMap<>();
private HashMap<String, ValueEventListener> valueEventListeners = new HashMap<>();

/**
* RNFirebase wrapper around FirebaseDatabaseReference,
* handles Query generation and event listeners.
*
* @param context
* @param app
* @param refKey
* @param refPath
* @param modifiersArray
*/
RNFirebaseDatabaseReference(
ReactContext context,
String app,
String url,
String refKey,
Expand All @@ -58,10 +56,10 @@ class RNFirebaseDatabaseReference {
query = null;
appName = app;
dbURL = url;
reactContext = context;
buildDatabaseQueryAtPathAndModifiers(refPath, modifiersArray);
}


/**
* Used outside of class for keepSynced etc.
*
Expand Down Expand Up @@ -109,6 +107,26 @@ void removeEventListener(String eventRegistrationKey) {
}
}

void removeAllEventListeners() {
if (hasListeners()) {
Iterator valueIterator = valueEventListeners.entrySet().iterator();
while (valueIterator.hasNext()) {
Map.Entry pair = (Map.Entry) valueIterator.next();
ValueEventListener valueEventListener = (ValueEventListener) pair.getValue();
query.removeEventListener(valueEventListener);
valueIterator.remove();
}

Iterator childIterator = childEventListeners.entrySet().iterator();
while (childIterator.hasNext()) {
Map.Entry pair = (Map.Entry) childIterator.next();
ChildEventListener childEventListener = (ChildEventListener) pair.getValue();
query.removeEventListener(childEventListener);
childIterator.remove();
}
}
}

/**
* Add a ValueEventListener to the query and internally keep a reference to it.
*
Expand Down Expand Up @@ -140,7 +158,6 @@ private void addEventListener(String eventRegistrationKey, ChildEventListener li
*/
private void addOnceValueEventListener(final Promise promise) {
@SuppressLint("StaticFieldLeak") final DataSnapshotToMapAsyncTask asyncTask = new DataSnapshotToMapAsyncTask(
reactContext,
this
) {
@Override
Expand Down Expand Up @@ -337,7 +354,7 @@ private void handleDatabaseEvent(
@Nullable String previousChildName
) {
@SuppressLint("StaticFieldLeak")
DataSnapshotToMapAsyncTask asyncTask = new DataSnapshotToMapAsyncTask(reactContext, this) {
DataSnapshotToMapAsyncTask asyncTask = new DataSnapshotToMapAsyncTask(this) {
@Override
protected void onPostExecute(WritableMap data) {
if (this.isAvailable()) {
Expand All @@ -346,7 +363,11 @@ protected void onPostExecute(WritableMap data) {
event.putString("key", key);
event.putString("eventType", eventType);
event.putMap("registration", Utils.readableMapToWritableMap(registration));
Utils.sendEvent(reactContext, "database_sync_event", event);
Utils.sendEvent(
RNFirebaseDatabase.getInstance().reactContext,
"database_sync_event",
event
);
}
}
};
Expand All @@ -366,7 +387,7 @@ private void handleDatabaseError(ReadableMap registration, DatabaseError error)
event.putMap("error", RNFirebaseDatabase.getJSError(error));
event.putMap("registration", Utils.readableMapToWritableMap(registration));

Utils.sendEvent(reactContext, "database_sync_event", event);
Utils.sendEvent(RNFirebaseDatabase.getInstance().reactContext, "database_sync_event", event);
}

/**
Expand Down Expand Up @@ -553,13 +574,10 @@ private void applyStartAtFilter(String key, String valueType, Map modifier) {
* Introduced due to https://github.com/invertase/react-native-firebase/issues/1284
*/
private static class DataSnapshotToMapAsyncTask extends AsyncTask<Object, Void, WritableMap> {

private WeakReference<ReactContext> reactContextWeakReference;
private WeakReference<RNFirebaseDatabaseReference> referenceWeakReference;

DataSnapshotToMapAsyncTask(ReactContext context, RNFirebaseDatabaseReference reference) {
DataSnapshotToMapAsyncTask(RNFirebaseDatabaseReference reference) {
referenceWeakReference = new WeakReference<>(reference);
reactContextWeakReference = new WeakReference<>(context);
}

@Override
Expand All @@ -571,9 +589,7 @@ protected final WritableMap doInBackground(Object... params) {
return RNFirebaseDatabaseUtils.snapshotToMap(dataSnapshot, previousChildName);
} catch (RuntimeException e) {
if (isAvailable()) {
reactContextWeakReference
.get()
.handleException(e);
RNFirebaseDatabase.getInstance().reactContext.handleException(e);
}
throw e;
}
Expand All @@ -585,7 +601,7 @@ protected void onPostExecute(WritableMap writableMap) {
}

Boolean isAvailable() {
return reactContextWeakReference.get() != null && referenceWeakReference.get() != null;
return RNFirebaseDatabase.getInstance() != null && referenceWeakReference.get() != null;
}
}
}