@@ -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