Skip to content

Commit 2f8ee50

Browse files
SUPERCILEXsamtstern
authored andcommitted
Fix tons of bugs relating to null snapshot.values and improve perf for good citizens (#871)
1 parent 74b0a8e commit 2f8ee50

File tree

3 files changed

+46
-28
lines changed

3 files changed

+46
-28
lines changed

app/src/main/java/com/firebase/uidemo/database/ChatIndexActivity.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.firebase.uidemo.database;
22

3-
import android.os.Bundle;
43
import android.view.View;
54

65
import com.firebase.ui.database.FirebaseIndexRecyclerAdapter;
@@ -13,12 +12,6 @@
1312
public class ChatIndexActivity extends ChatActivity {
1413
private DatabaseReference mChatIndicesRef;
1514

16-
@Override
17-
protected void onCreate(Bundle savedInstanceState) {
18-
super.onCreate(savedInstanceState);
19-
mChatIndicesRef = FirebaseDatabase.getInstance().getReference().child("chatIndices");
20-
}
21-
2215
@Override
2316
public void onClick(View v) {
2417
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
@@ -34,6 +27,11 @@ public void onClick(View v) {
3427

3528
@Override
3629
protected FirebaseRecyclerAdapter<Chat, ChatHolder> getAdapter() {
30+
mChatIndicesRef = FirebaseDatabase.getInstance()
31+
.getReference()
32+
.child("chatIndices")
33+
.child(FirebaseAuth.getInstance().getCurrentUser().getUid());
34+
3735
return new FirebaseIndexRecyclerAdapter<Chat, ChatHolder>(
3836
Chat.class,
3937
R.layout.message,

database/src/main/java/com/firebase/ui/database/FirebaseArray.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,11 @@ public void onChildMoved(DataSnapshot snapshot, String previousChildKey) {
110110
int oldIndex = getIndexForKey(snapshot.getKey());
111111
mSnapshots.remove(oldIndex);
112112

113-
int newIndex = previousChildKey == null ? 0 : (getIndexForKey(previousChildKey) + 1);
113+
int newIndex = previousChildKey == null ? 0 : getIndexForKey(previousChildKey) + 1;
114114
mSnapshots.add(newIndex, snapshot);
115115

116-
notifyChangeEventListeners(ChangeEventListener.EventType.MOVED,
117-
snapshot,
118-
newIndex,
119-
oldIndex);
116+
notifyChangeEventListeners(
117+
ChangeEventListener.EventType.MOVED, snapshot, newIndex, oldIndex);
120118
}
121119

122120
@Override

database/src/main/java/com/firebase/ui/database/FirebaseIndexArray.java

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -140,18 +140,32 @@ protected List<DataSnapshot> getSnapshots() {
140140
return mDataSnapshots;
141141
}
142142

143-
private int getIndexForKey(String key) {
144-
int dataCount = size();
145-
int index = 0;
146-
for (int keyIndex = 0; index < dataCount; keyIndex++) {
147-
String superKey = mKeySnapshots.getObject(keyIndex);
148-
if (key.equals(superKey)) {
149-
break;
150-
} else if (mDataSnapshots.get(index).getKey().equals(superKey)) {
151-
index++;
143+
private int returnOrFindIndexForKey(int index, String key) {
144+
int realIndex;
145+
if (isKeyAtIndex(key, index)) {
146+
// To optimize this query, if the expected item position is accurate, we simply return
147+
// it instead of searching for it in our keys all over again. This ensures developers
148+
// correctly indexing their data (i.e. no null values) don't take a performance hit.
149+
realIndex = index;
150+
} else {
151+
int dataCount = size();
152+
int dataIndex = 0;
153+
int keyIndex = 0;
154+
155+
while (dataIndex < dataCount && keyIndex < mKeySnapshots.size()) {
156+
String superKey = mKeySnapshots.getObject(keyIndex);
157+
if (key.equals(superKey)) {
158+
break;
159+
} else if (mDataSnapshots.get(dataIndex).getKey().equals(superKey)) {
160+
// Only increment the data index if we aren't passing over a null value snapshot.
161+
dataIndex++;
162+
}
163+
keyIndex++;
152164
}
165+
166+
realIndex = dataIndex;
153167
}
154-
return index;
168+
return realIndex;
155169
}
156170

157171
/**
@@ -173,11 +187,15 @@ protected void onKeyAdded(DataSnapshot data) {
173187
protected void onKeyMoved(DataSnapshot data, int index, int oldIndex) {
174188
String key = data.getKey();
175189

190+
// We can't use `returnOrFindIndexForKey(...)` for `oldIndex` or it might find the updated
191+
// index instead of the old one. Unfortunately, this does mean move events will be
192+
// incorrectly ignored if our list is a subset of the key list e.g. a key has null data.
176193
if (isKeyAtIndex(key, oldIndex)) {
177194
DataSnapshot snapshot = removeData(oldIndex);
195+
int realIndex = returnOrFindIndexForKey(index, key);
178196
mHasPendingMoveOrDelete = true;
179-
mDataSnapshots.add(index, snapshot);
180-
notifyChangeEventListeners(EventType.MOVED, snapshot, index, oldIndex);
197+
mDataSnapshots.add(realIndex, snapshot);
198+
notifyChangeEventListeners(EventType.MOVED, snapshot, realIndex, oldIndex);
181199
}
182200
}
183201

@@ -186,10 +204,11 @@ protected void onKeyRemoved(DataSnapshot data, int index) {
186204
ValueEventListener listener = mRefs.remove(mDataRef.getRef().child(key));
187205
if (listener != null) mDataRef.child(key).removeEventListener(listener);
188206

189-
if (isKeyAtIndex(key, index)) {
190-
DataSnapshot snapshot = removeData(index);
207+
int realIndex = returnOrFindIndexForKey(index, key);
208+
if (isKeyAtIndex(key, realIndex)) {
209+
DataSnapshot snapshot = removeData(realIndex);
191210
mHasPendingMoveOrDelete = true;
192-
notifyChangeEventListeners(EventType.REMOVED, snapshot, index);
211+
notifyChangeEventListeners(EventType.REMOVED, snapshot, realIndex);
193212
}
194213
}
195214

@@ -225,10 +244,13 @@ public String toString() {
225244
* A ValueEventListener attached to the joined child data.
226245
*/
227246
protected class DataRefListener implements ValueEventListener {
247+
/** Cached index to skip searching for the current index on each update */
248+
private int currentIndex;
249+
228250
@Override
229251
public void onDataChange(DataSnapshot snapshot) {
230252
String key = snapshot.getKey();
231-
int index = getIndexForKey(key);
253+
int index = currentIndex = returnOrFindIndexForKey(currentIndex, key);
232254

233255
if (snapshot.getValue() != null) {
234256
if (isKeyAtIndex(key, index)) {

0 commit comments

Comments
 (0)