Skip to content

Add a callback in FirebaseIndexArray when a Key doesn't exist in a ref #448

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

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
28c366c
Add a callback in FirebaseIndexArray when a Key doesn't exist in a ref
SUPERCILEX Dec 9, 2016
641297c
Add documentation
SUPERCILEX Dec 9, 2016
a62a025
Rename listeners
SUPERCILEX Dec 14, 2016
703f85d
Merge remote-tracking branch 'firebase/version-1.1.0-dev' into db-cal…
SUPERCILEX Dec 14, 2016
f1e702b
Add JoinResolver.java interface
SUPERCILEX Dec 15, 2016
af39a1e
Cleanup
SUPERCILEX Dec 15, 2016
25fc4df
Rename ChangeListener to ChangeEventListener
SUPERCILEX Dec 15, 2016
5486e8c
Cleanup
SUPERCILEX Dec 15, 2016
23806d7
Make JoinResolver.java public
SUPERCILEX Dec 15, 2016
06fb7d0
Merge remote-tracking branch 'firebase/version-1.1.0-dev' into db-cal…
SUPERCILEX Dec 16, 2016
0b56e99
Merge remote-tracking branch 'firebase/version-1.1.0-dev' into db-cal…
SUPERCILEX Dec 22, 2016
331b4bf
Rename
SUPERCILEX Jan 3, 2017
f396fec
Merge remote-tracking branch 'firebase/version-1.1.0-dev' into db-cal…
SUPERCILEX Jan 3, 2017
cfdb305
Fix compile error
SUPERCILEX Jan 3, 2017
cc3729c
Merge branch 'version-1.1.0-dev' into db-callback
SUPERCILEX Jan 5, 2017
f5d06b2
Merge remote-tracking branch 'firebase/version-1.1.0-dev' into db-cal…
SUPERCILEX Jan 9, 2017
de52c1d
Merge remote-tracking branch 'firebase/version-1.1.0-dev' into db-cal…
SUPERCILEX Jan 11, 2017
97d9cb0
Fix merge mistakes
SUPERCILEX Jan 11, 2017
e7297d4
Merge remote-tracking branch 'firebase/master' into db-callback
SUPERCILEX Jan 13, 2017
9a03342
Merge remote-tracking branch 'firebase/master' into db-callback
SUPERCILEX Jan 17, 2017
8f87492
Merge branch 'version-1.2.0-dev' of https://github.com/firebase/Fireb…
SUPERCILEX Jan 22, 2017
dcf96bf
Merge remote-tracking branch 'firebase/version-1.2.0-dev' into db-cal…
SUPERCILEX Jan 25, 2017
48ea75a
Fix a ton of merge mistakes
SUPERCILEX Jan 25, 2017
4a5a1be
Provide default join resolver
SUPERCILEX Jan 25, 2017
dbbf0dc
Fix tests and bugs
SUPERCILEX Jan 25, 2017
b37c8bd
Cleanup
SUPERCILEX Jan 25, 2017
d25245b
More cleanup
SUPERCILEX Jan 25, 2017
7e01eb1
Fix spacing
SUPERCILEX Jan 25, 2017
f09383f
Merge remote-tracking branch 'firebase/version-2.0.0-dev' into db-cal…
SUPERCILEX Mar 6, 2017
03c14d2
Fix merge mistakes
SUPERCILEX Mar 6, 2017
63d5ca5
Fixups
SUPERCILEX Mar 6, 2017
14e3443
Merge remote-tracking branch 'firebase/version-2.0.0-dev' into db-cal…
SUPERCILEX Mar 6, 2017
ab613bd
Cleanup
SUPERCILEX Mar 10, 2017
64bfb37
Merge remote-tracking branch 'firebase/version-2.0.0-dev' into db-cal…
SUPERCILEX Mar 10, 2017
ae83d83
Merge remote-tracking branch 'firebase/version-2.0.0-dev' into db-cal…
SUPERCILEX Mar 13, 2017
371c211
Cleanup
SUPERCILEX Mar 14, 2017
dbc1a43
Merge remote-tracking branch 'firebase/version-2.0.0-dev' into db-cal…
SUPERCILEX Mar 14, 2017
0a1d2b5
Merge remote-tracking branch 'upstream/version-2.0.0-dev' into db-cal…
SUPERCILEX Apr 24, 2017
53920a2
Merge remote-tracking branch 'upstream/version-2.0.0-dev' into db-cal…
SUPERCILEX Apr 26, 2017
b3c137f
Flip onJoinFailed params to make more sense
SUPERCILEX Apr 26, 2017
c23eec1
Merge remote-tracking branch 'upstream/version-2.0.0-dev' into db-cal…
SUPERCILEX May 2, 2017
d2962fa
Merge remote-tracking branch 'upstream/version-2.0.0-dev' into db-cal…
SUPERCILEX May 9, 2017
52b7c10
Merge remote-tracking branch 'upstream/version-2.0.0-dev' into db-cal…
SUPERCILEX May 13, 2017
f236047
Merge remote-tracking branch 'upstream/version-2.0.0-dev' into db-cal…
SUPERCILEX Jun 2, 2017
2933598
Merge remote-tracking branch 'upstream/version-2.0.0-dev' into db-cal…
SUPERCILEX Jun 5, 2017
a2909e4
Merge remote-tracking branch 'upstream/version-2.0.0-dev' into db-cal…
SUPERCILEX Jun 9, 2017
a11975c
Merge remote-tracking branch 'upstream/master' into db-callback
SUPERCILEX Jun 12, 2017
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 @@ -14,6 +14,7 @@

package com.firebase.ui.database;

import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
Expand All @@ -36,6 +37,7 @@ public class FirebaseIndexArray<T> extends CachingObservableSnapshotArray<T> imp
private Map<DatabaseReference, ValueEventListener> mRefs = new HashMap<>();

private FirebaseArray<String> mKeySnapshots;
private JoinResolver mJoinResolver;
private List<DataSnapshot> mDataSnapshots = new ArrayList<>();

/**
Expand All @@ -52,13 +54,44 @@ public class FirebaseIndexArray<T> extends CachingObservableSnapshotArray<T> imp
private boolean mHasPendingMoveOrDelete;

/**
* Create a new FirebaseIndexArray that parses snapshots as members of a given class.
* Create a new FirebaseIndexArray with a custom {@link SnapshotParser} and {@link
* JoinResolver}.
*
* @param keyQuery The Firebase location containing the list of keys to be found in {@code
* dataRef}. Can also be a slice of a location, using some combination of {@code
* limit()}, {@code startAt()}, and {@code endAt()}.
* @param dataRef The Firebase location to watch for data changes. Each key key found at {@code
* keyQuery}'s location represents a list item in the {@link RecyclerView}.
* @see ObservableSnapshotArray#ObservableSnapshotArray(SnapshotParser)
*/
public FirebaseIndexArray(Query keyQuery,
DatabaseReference dataRef,
SnapshotParser<T> parser,
JoinResolver resolver) {
super(parser);
init(keyQuery, dataRef, resolver);
}

/**
* Create a new FirebaseIndexArray that parses snapshots as members of a given class and joins
* refs together with a custom {@link JoinResolver}.
*
* @see FirebaseIndexArray#FirebaseIndexArray(Query, DatabaseReference, SnapshotParser,
* JoinResolver)
* @see ObservableSnapshotArray#ObservableSnapshotArray(Class)
*/
public FirebaseIndexArray(Query keyQuery,
DatabaseReference dataRef,
Class<T> tClass,
JoinResolver resolver) {
super(tClass);
init(keyQuery, dataRef, resolver);
}

/**
* Create a new FirebaseIndexArray that parses snapshots as members of a given class.
*
* @see FirebaseIndexArray#FirebaseIndexArray(Query, DatabaseReference, Class, JoinResolver)
* @see ObservableSnapshotArray#ObservableSnapshotArray(Class)
*/
public FirebaseIndexArray(Query keyQuery, DatabaseReference dataRef, Class<T> tClass) {
Expand All @@ -69,16 +102,24 @@ public FirebaseIndexArray(Query keyQuery, DatabaseReference dataRef, Class<T> tC
/**
* Create a new FirebaseIndexArray with a custom {@link SnapshotParser}.
*
* @see FirebaseIndexArray#FirebaseIndexArray(Query, DatabaseReference, SnapshotParser,
* JoinResolver)
* @see ObservableSnapshotArray#ObservableSnapshotArray(SnapshotParser)
* @see FirebaseIndexArray#FirebaseIndexArray(Query, DatabaseReference, Class)
*/
public FirebaseIndexArray(Query keyQuery, DatabaseReference dataRef, SnapshotParser<T> parser) {
super(parser);
init(keyQuery, dataRef);
}

private void init(Query keyQuery, DatabaseReference dataRef) {
@CallSuper
protected void init(Query keyQuery, DatabaseReference dataRef) {
init(keyQuery, dataRef, new DefaultJoinResolver());
}

@CallSuper
protected void init(Query keyQuery, DatabaseReference dataRef, JoinResolver resolver) {
mDataRef = dataRef;
mJoinResolver = resolver;
mKeySnapshots = new FirebaseArray<>(keyQuery, new SnapshotParser<String>() {
@Override
public String parseSnapshot(DataSnapshot snapshot) {
Expand Down Expand Up @@ -166,10 +207,9 @@ private boolean isKeyAtIndex(String key, int index) {
}

protected void onKeyAdded(DataSnapshot data) {
String key = data.getKey();
DatabaseReference ref = mDataRef.child(key);
DatabaseReference ref = mJoinResolver.onJoin(data);

mKeysWithPendingData.add(key);
mKeysWithPendingData.add(data.getKey());
// Start listening
mRefs.put(ref, ref.addValueEventListener(new DataRefListener()));
}
Expand All @@ -186,11 +226,11 @@ protected void onKeyMoved(DataSnapshot data, int index, int oldIndex) {
}

protected void onKeyRemoved(DataSnapshot data, int index) {
String key = data.getKey();
ValueEventListener listener = mRefs.remove(mDataRef.getRef().child(key));
if (listener != null) mDataRef.child(key).removeEventListener(listener);
DatabaseReference removeRef = mJoinResolver.onDisjoin(data);
ValueEventListener listener = mRefs.remove(removeRef);
if (listener != null) removeRef.removeEventListener(listener);

if (isKeyAtIndex(key, index)) {
if (isKeyAtIndex(data.getKey(), index)) {
DataSnapshot snapshot = removeData(index);
mHasPendingMoveOrDelete = true;
notifyChangeEventListeners(EventType.REMOVED, snapshot, index);
Expand Down Expand Up @@ -256,7 +296,7 @@ public void onDataChange(DataSnapshot snapshot) {
notifyListenersOnDataChanged();
} else {
// Data does not exist
Log.w(TAG, "Key not found at ref: " + snapshot.getRef());
mJoinResolver.onJoinFailed(snapshot, index);
}
}
}
Expand All @@ -266,4 +306,23 @@ public void onCancelled(DatabaseError error) {
notifyListenersOnCancelled(error);
}
}

protected class DefaultJoinResolver implements JoinResolver {
@NonNull
@Override
public DatabaseReference onJoin(DataSnapshot keySnapshot) {
return mDataRef.child(keySnapshot.getKey());
}

@NonNull
@Override
public DatabaseReference onDisjoin(DataSnapshot keySnapshot) {
return onJoin(keySnapshot); // Match the join/disjoin pair
}

@Override
public void onJoinFailed(DataSnapshot snapshot, int index) {
Log.w(TAG, "Key not found at ref " + snapshot.getRef() + " for index " + index);
}
}
}
43 changes: 43 additions & 0 deletions database/src/main/java/com/firebase/ui/database/JoinResolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.firebase.ui.database;

import android.support.annotation.NonNull;

import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseReference;

/**
* Handles joining two queries together.
*/
public interface JoinResolver {
/**
* Called after an {@link ChildEventListener#onChildAdded(DataSnapshot, String)} event from
* {@code keyRef}.
*
* @param keySnapshot the snapshot supplied in {@code onChildAdded}
* @return A query containing the joined data from the {@code keyRef}'s indexed snapshot.
* <p>Without any customization, a query on the child from your {@code dataRef} with the key
* found in {@code keySnapshot} will be returned.
*/
@NonNull
DatabaseReference onJoin(DataSnapshot keySnapshot);

/**
* Called after an {@link ChildEventListener#onChildRemoved(DataSnapshot)} event from {@code
* keyRef}.
*
* @param keySnapshot the snapshot supplied in {@code onChildRemoved}
* @return The same query supplied in {@code onJoin} for the given {@code keySnapshot}.
*/
@NonNull
DatabaseReference onDisjoin(DataSnapshot keySnapshot);

/**
* Called when a key in {@code keyRef} could not be found in {@code dataRef}.
*
* @param snapshot the snapshot who's key could not be found in {@code dataRef}
* @param index index of a {@link DataSnapshot} in {@code keyRef} that could not be found in
* {@code dataRef}
*/
void onJoinFailed(DataSnapshot snapshot, int index);
}