3

While learning to iterate over a cursor, I learned that I needed to first move to position "-1" and then use "moveToNext" in a loop:

cursor.moveToPosition(-1);
for (int i = 0; cursor.moveToNext(); i++) {
  //do something with the cursor
}

While mathematically this makes sense, I don't know what it means to move to a cursor to a negative position. The documentation just says it's valid–doesn't seem to say how it's used.

Is this used ONLY to make iteration possible, or is there other use cases for the position -1?

Community
  • 1
  • 1
adamdport
  • 11,687
  • 14
  • 69
  • 91
  • This is pretty standard for cursors: the cursor starts before the first row (which has index 0). http://stackoverflow.com/a/10723771/139010 – Matt Ball Dec 17 '14 at 16:27
  • you dont move to a negative position you move it to the first position `cursor.moveToFirst()` aka 0 – tyczj Dec 17 '14 at 16:27
  • @tyczj if I moved to the first position and there was only one position, I'd never enter the loop. – adamdport Dec 17 '14 at 16:29
  • because you move to the next positon before you do the first one so you skip the first position – tyczj Dec 17 '14 at 16:29
  • `I learned that I needed to first move to position "-1"` I don't see much in the linked question that could lead you to believe that. Use moveToFirst and a while loop. – njzk2 Dec 17 '14 at 16:40
  • 1
    @njzk2 I believe @adamdport is referring to [my comment on the accepted answer to that question](http://stackoverflow.com/questions/10723770/whats-the-best-way-to-iterate-an-android-cursor/10723771#comment33274077_10723771). Basically there are 2 clean ways to iterate: (a) `moveToPosition(-1)` followed by a while loop, and, (b) `moveToFirst` followed by a do-while loop. – Vicky Chijwani Dec 17 '14 at 19:35
  • @VickyChijwani: i don't consider `moveToPosition(-1)` to be clean, as it involves a magic number. A `moveToBeforeFirst` is really missing. – njzk2 Dec 17 '14 at 19:40
  • @njzk2 Agreed. But `moveToFirst` + do-while loop won't work either, I just realized. If there are no items in the cursor, the do-while loop will still start an iteration and end up throwing an error. My mistake there. So that leaves option (a) only. – Vicky Chijwani Dec 17 '14 at 19:44
  • 2
    @VickyChijwani moveToFirst does work if you wrap it in an if statement, there is a reason moveToFirst returns a boolean you shouldnt just ignore it – tyczj Dec 17 '14 at 19:46

4 Answers4

3

A cursor should not be at a negative position, a cursors data starts at position 0 which is why you always need to move the cursor to the first position before getting the data using

if(cursor.moveToFirst()){
    //you have data in the cursor
}

now to go through the cursor just simply use a do/while loop

do{
    //process cursor data
}while(cursor.moveToNext);

what you are doing with your for loop breaks that convention, if you move your cursor to the first position then try executing your for loop the cursor will try to move to the next position before you even process the first position. This is why you dont enter the for loop when you have 1 thing in the cursor

Zon
  • 18,610
  • 7
  • 91
  • 99
tyczj
  • 71,600
  • 54
  • 194
  • 296
  • 1
    If it "should not be at a negative position", why does "moveToPosition" accept -1? – adamdport Dec 17 '14 at 18:14
  • because its the default starting position no matter if there is or isnt data – tyczj Dec 17 '14 at 18:16
  • 1
    It will accept any negative number, but if the number is negative it will default to -1. The code inside the cursor checks if position < 0, if it is it sets its instance variable mPos to -1 (the default) which allows the other methods to work as expected. – DejanRistic Dec 17 '14 at 18:23
  • @DejanRistic so did I use it as it was intended to be used then? – adamdport Dec 17 '14 at 18:42
  • @adamdport no the correct way to use a cursor is to move it to the first position – tyczj Dec 17 '14 at 18:44
  • 2
    Well you don't want to use a for loop, a while loop makes more sense since the method returns a boolean. This way you don't have to worry about the i. When you create a cursor, it should default to -1, its in the constructor to most known subclasses of Cursor (interface). So it should already be at -1. So unless the cursor is null or it has been moved before, moveToNext() will move it to 0 if it can. So you could just use moveToNext(). moveToFirst() can be more readable sometimes if people don't understand how it works. also it could be useful if you want to move it to the first position. – DejanRistic Dec 17 '14 at 18:49
  • I've seen it used without moveToFirst() in Google applications that are open source, such as the Google I/O 2014 application. See link below for example (line 102). https://github.com/google/iosched/blob/0a90bf8e6b90e9226f8c15b34eb7b1e4bf6d632e/android/src/main/java/com/google/samples/apps/iosched/model/ScheduleHelper.java – DejanRistic Dec 17 '14 at 18:50
  • @DejanRistic I wouldn't recommend using the cursor without `moveToPosition(-1)` or `moveToFirst()`. For example if you're using a `CursorLoader`, the loader re-uses the same `Cursor` instance so you must reset it before iterating. See [my comment elsewhere](http://stackoverflow.com/questions/10723770/whats-the-best-way-to-iterate-an-android-cursor/10723771#comment33274077_10723771) for more details. – Vicky Chijwani Dec 17 '14 at 19:48
  • @VickyChijwani, good point. If you know the cursor may not be in the default position you should use moveToFirst(). It depends on the type of cursor, that one extra call isn't hurting anyones performance. – DejanRistic Dec 17 '14 at 20:18
1

The -1 index in cursors is the default starting position and the fallback position. Calling moveToFirst will always move to position 0 if it exists. You want to make sure if you do use moveToFirst, you process that entry then call moveToNext.

if(cursor.moveToFirst()){ // moves to 0, process it.
    process(...);
  while(cursor.moveToNext()){ // moves to 1...n, process them.
     process(...);
   }
 }

That is just one way to approach it, hope it helps.

Good Luck

DejanRistic
  • 2,039
  • 18
  • 13
  • 3
    Using this method, I have to repeat `process(...);`. Seems like a code smell to me. – adamdport Dec 17 '14 at 18:11
  • well process is a method, so it would be called the same amount of times regardless. It will be called sizeOf(cursor) times. moveToNext actually just calls moveToPosition(mPos + 1) internally, so you could just use moveToNext() if you know that the cursor is not null and its at -1. – DejanRistic Dec 17 '14 at 18:29
1

I suspect that default cursor position was intentionally set to -1 to make us able to iterate with just while(cursor.moveToNext()) {...}. There is no other reasons to have negative positions of cursor.

You don't need to reset position to -1 as long as you haven't affect this cursor before.

Vasily Makarov
  • 311
  • 2
  • 11
0

-1 is the default position of a cursor and you always need to move the cursor to the first position ie 0th index. To perform your activity

cursor.moveToFirst(); //moves the cursor to the first position

Now to iterate

while(cursor.moveToNext())//when there's a value in cursor.moveToNext
{
//your action to be performed
}
Mithil Mohan
  • 223
  • 2
  • 11
  • 1
    In your code cursor.moveToPosition(-1) and subsequent cursor.moveToNext() is equivalent to statement cursor.moveToFirst() which directly moves cursor to position 0 – Mithil Mohan Dec 17 '14 at 17:23
  • 2
    Correct me if I'm wrong, but this method will skip the first element, or simply never enter the loop if there is only one element. – adamdport Dec 17 '14 at 19:55