@@ -141,18 +141,32 @@ protected List<DataSnapshot> getSnapshots() {
141
141
return mDataSnapshots ;
142
142
}
143
143
144
- private int getIndexForKey (String key ) {
145
- int dataCount = size ();
146
- int index = 0 ;
147
- for (int keyIndex = 0 ; index < dataCount ; keyIndex ++) {
148
- String superKey = mKeySnapshots .getObject (keyIndex );
149
- if (key .equals (superKey )) {
150
- break ;
151
- } else if (mDataSnapshots .get (index ).getKey ().equals (superKey )) {
152
- index ++;
144
+ private int returnOrFindIndexForKey (int index , String key ) {
145
+ int realIndex ;
146
+ if (isKeyAtIndex (key , index )) {
147
+ // To optimize this query, if the expected item position is accurate, we simply return
148
+ // it instead of searching for it in our keys all over again. This ensures developers
149
+ // correctly indexing their data (i.e. no null values) don't take a performance hit.
150
+ realIndex = index ;
151
+ } else {
152
+ int dataCount = size ();
153
+ int dataIndex = 0 ;
154
+ int keyIndex = 0 ;
155
+
156
+ while (dataIndex < dataCount && keyIndex < mKeySnapshots .size ()) {
157
+ String superKey = mKeySnapshots .getObject (keyIndex );
158
+ if (key .equals (superKey )) {
159
+ break ;
160
+ } else if (mDataSnapshots .get (dataIndex ).getKey ().equals (superKey )) {
161
+ // Only increment the data index if we aren't passing over a null value snapshot.
162
+ dataIndex ++;
163
+ }
164
+ keyIndex ++;
153
165
}
166
+
167
+ realIndex = dataIndex ;
154
168
}
155
- return index ;
169
+ return realIndex ;
156
170
}
157
171
158
172
/**
@@ -174,10 +188,15 @@ protected void onKeyAdded(DataSnapshot data) {
174
188
protected void onKeyMoved (DataSnapshot data , int index , int oldIndex ) {
175
189
String key = data .getKey ();
176
190
191
+ // We can't use `returnOrFindIndexForKey(...)` for `oldIndex` or it might find the updated
192
+ // index instead of the old one. Unfortunately, this does mean move events will be
193
+ // incorrectly ignored if our list is a subset of the key list e.g. a key has null data.
177
194
if (isKeyAtIndex (key , oldIndex )) {
178
195
DataSnapshot snapshot = removeData (oldIndex );
196
+ int realIndex = returnOrFindIndexForKey (index , key );
179
197
mHasPendingMoveOrDelete = true ;
180
- mDataSnapshots .add (index , snapshot );
198
+
199
+ mDataSnapshots .add (realIndex , snapshot );
181
200
notifyListenersOnChildChanged (ChangeEventType .MOVED , snapshot , index , oldIndex );
182
201
}
183
202
}
@@ -187,10 +206,11 @@ protected void onKeyRemoved(DataSnapshot data, int index) {
187
206
ValueEventListener listener = mRefs .remove (mDataRef .getRef ().child (key ));
188
207
if (listener != null ) mDataRef .child (key ).removeEventListener (listener );
189
208
190
- if (isKeyAtIndex (key , index )) {
191
- DataSnapshot snapshot = removeData (index );
209
+ int realIndex = returnOrFindIndexForKey (index , key );
210
+ if (isKeyAtIndex (key , realIndex )) {
211
+ DataSnapshot snapshot = removeData (realIndex );
192
212
mHasPendingMoveOrDelete = true ;
193
- notifyListenersOnChildChanged (ChangeEventType .REMOVED , snapshot , index , -1 );
213
+ notifyListenersOnChildChanged (ChangeEventType .REMOVED , snapshot , realIndex , -1 );
194
214
}
195
215
}
196
216
@@ -236,10 +256,13 @@ public String toString() {
236
256
* A ValueEventListener attached to the joined child data.
237
257
*/
238
258
protected class DataRefListener implements ValueEventListener {
259
+ /** Cached index to skip searching for the current index on each update */
260
+ private int currentIndex ;
261
+
239
262
@ Override
240
263
public void onDataChange (DataSnapshot snapshot ) {
241
264
String key = snapshot .getKey ();
242
- int index = getIndexForKey ( key );
265
+ int index = currentIndex = returnOrFindIndexForKey ( currentIndex , key );
243
266
244
267
if (snapshot .getValue () != null ) {
245
268
if (isKeyAtIndex (key , index )) {
0 commit comments