-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Fix tons of bugs relating to null snapshot.value
s and improve perf for good citizens
#871
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
Changes from all commits
10dcc40
fe5a4c0
5abafa4
c216565
eb74c76
9dbd38b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,18 +140,32 @@ protected List<DataSnapshot> getSnapshots() { | |
return mDataSnapshots; | ||
} | ||
|
||
private int getIndexForKey(String key) { | ||
int dataCount = size(); | ||
int index = 0; | ||
for (int keyIndex = 0; index < dataCount; keyIndex++) { | ||
String superKey = mKeySnapshots.getObject(keyIndex); | ||
if (key.equals(superKey)) { | ||
break; | ||
} else if (mDataSnapshots.get(index).getKey().equals(superKey)) { | ||
index++; | ||
private int returnOrFindIndexForKey(int index, String key) { | ||
int realIndex; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we initialize realIndex to 0 for clarity? If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm, we could but intellij complains because we do initialize it to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh oops I missed that, thanks! |
||
if (isKeyAtIndex(key, index)) { | ||
// To optimize this query, if the expected item position is accurate, we simply return | ||
// it instead of searching for it in our keys all over again. This ensures developers | ||
// correctly indexing their data (i.e. no null values) don't take a performance hit. | ||
realIndex = index; | ||
} else { | ||
int dataCount = size(); | ||
int dataIndex = 0; | ||
int keyIndex = 0; | ||
|
||
while (dataIndex < dataCount && keyIndex < mKeySnapshots.size()) { | ||
String superKey = mKeySnapshots.getObject(keyIndex); | ||
if (key.equals(superKey)) { | ||
break; | ||
} else if (mDataSnapshots.get(dataIndex).getKey().equals(superKey)) { | ||
// Only increment the data index if we aren't passing over a null value snapshot. | ||
dataIndex++; | ||
} | ||
keyIndex++; | ||
} | ||
|
||
realIndex = dataIndex; | ||
} | ||
return index; | ||
return realIndex; | ||
} | ||
|
||
/** | ||
|
@@ -173,11 +187,15 @@ protected void onKeyAdded(DataSnapshot data) { | |
protected void onKeyMoved(DataSnapshot data, int index, int oldIndex) { | ||
String key = data.getKey(); | ||
|
||
// We can't use `returnOrFindIndexForKey(...)` for `oldIndex` or it might find the updated | ||
// index instead of the old one. Unfortunately, this does mean move events will be | ||
// incorrectly ignored if our list is a subset of the key list e.g. a key has null data. | ||
if (isKeyAtIndex(key, oldIndex)) { | ||
DataSnapshot snapshot = removeData(oldIndex); | ||
int realIndex = returnOrFindIndexForKey(index, key); | ||
mHasPendingMoveOrDelete = true; | ||
mDataSnapshots.add(index, snapshot); | ||
notifyChangeEventListeners(EventType.MOVED, snapshot, index, oldIndex); | ||
mDataSnapshots.add(realIndex, snapshot); | ||
notifyChangeEventListeners(EventType.MOVED, snapshot, realIndex, oldIndex); | ||
} | ||
} | ||
|
||
|
@@ -186,10 +204,11 @@ protected void onKeyRemoved(DataSnapshot data, int index) { | |
ValueEventListener listener = mRefs.remove(mDataRef.getRef().child(key)); | ||
if (listener != null) mDataRef.child(key).removeEventListener(listener); | ||
|
||
if (isKeyAtIndex(key, index)) { | ||
DataSnapshot snapshot = removeData(index); | ||
int realIndex = returnOrFindIndexForKey(index, key); | ||
if (isKeyAtIndex(key, realIndex)) { | ||
DataSnapshot snapshot = removeData(realIndex); | ||
mHasPendingMoveOrDelete = true; | ||
notifyChangeEventListeners(EventType.REMOVED, snapshot, index); | ||
notifyChangeEventListeners(EventType.REMOVED, snapshot, realIndex); | ||
} | ||
} | ||
|
||
|
@@ -225,10 +244,13 @@ public String toString() { | |
* A ValueEventListener attached to the joined child data. | ||
*/ | ||
protected class DataRefListener implements ValueEventListener { | ||
/** Cached index to skip searching for the current index on each update */ | ||
private int currentIndex; | ||
|
||
@Override | ||
public void onDataChange(DataSnapshot snapshot) { | ||
String key = snapshot.getKey(); | ||
int index = getIndexForKey(key); | ||
int index = currentIndex = returnOrFindIndexForKey(currentIndex, key); | ||
|
||
if (snapshot.getValue() != null) { | ||
if (isKeyAtIndex(key, index)) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a
uid
to the indices to make them more realistic.