@@ -140,18 +140,32 @@ protected List<DataSnapshot> getSnapshots() {
140
140
return mDataSnapshots ;
141
141
}
142
142
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 ++;
152
164
}
165
+
166
+ realIndex = dataIndex ;
153
167
}
154
- return index ;
168
+ return realIndex ;
155
169
}
156
170
157
171
/**
@@ -173,11 +187,15 @@ protected void onKeyAdded(DataSnapshot data) {
173
187
protected void onKeyMoved (DataSnapshot data , int index , int oldIndex ) {
174
188
String key = data .getKey ();
175
189
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.
176
193
if (isKeyAtIndex (key , oldIndex )) {
177
194
DataSnapshot snapshot = removeData (oldIndex );
195
+ int realIndex = returnOrFindIndexForKey (index , key );
178
196
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 );
181
199
}
182
200
}
183
201
@@ -186,10 +204,11 @@ protected void onKeyRemoved(DataSnapshot data, int index) {
186
204
ValueEventListener listener = mRefs .remove (mDataRef .getRef ().child (key ));
187
205
if (listener != null ) mDataRef .child (key ).removeEventListener (listener );
188
206
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 );
191
210
mHasPendingMoveOrDelete = true ;
192
- notifyChangeEventListeners (EventType .REMOVED , snapshot , index );
211
+ notifyChangeEventListeners (EventType .REMOVED , snapshot , realIndex );
193
212
}
194
213
}
195
214
@@ -225,10 +244,13 @@ public String toString() {
225
244
* A ValueEventListener attached to the joined child data.
226
245
*/
227
246
protected class DataRefListener implements ValueEventListener {
247
+ /** Cached index to skip searching for the current index on each update */
248
+ private int currentIndex ;
249
+
228
250
@ Override
229
251
public void onDataChange (DataSnapshot snapshot ) {
230
252
String key = snapshot .getKey ();
231
- int index = getIndexForKey ( key );
253
+ int index = currentIndex = returnOrFindIndexForKey ( currentIndex , key );
232
254
233
255
if (snapshot .getValue () != null ) {
234
256
if (isKeyAtIndex (key , index )) {
0 commit comments