How does Java implement the moveToPrevious method on Cursor? - android

I came across a method on Cursor called moveToPrevious().
I had previously read an article which suggested that implementing a backwards version of the C SQLite step command would be hard / impossible:
... asking for an sqlite3_step_backward() button is really like expecting your symbolic debugger to be able to run backwards or to "undo" its execution back to the previous breakpoint. Nobody reasonably expects debuggers to be able to do this, so you shouldn't expect SQLite to be able to sqlite3_step_backward() either.
Is an Android cursor a wrapper around SQLite or some kind of a independent implementation?
How how have thay made this moveToPrevious command?

The Android Cursor class indeed reads all result records into memory first, and then allows you to step through them randomly.
(This is why there is the 1 MB limit on data in a cursor.)

Cursor interface provides random read-write access to the result set returned by a database query. Cursor implementations are not required to be synchronized so code using a Cursor from multiple threads should perform its own synchronization when using the Cursor.
Cursor: Retrieving data from SQLite databases in Android is done using Cursors. The Android SQLite query method returns a Cursor object containing the results of the query.Cursors store query result records in rows and grant many methods to access and iterate through the records.To use Cursors android.database.Cursor must be imported.
http://developer.android.com/reference/android/database/Cursor.html
Check the source here
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/android/database/Cursor.java/
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/android/database/AbstractCursor.java/
Look at the line 248 in the link
248 public final boolean moveToPrevious() {
249 return moveToPosition(mPos - 1);
// mPos looks like is the index here which is an int
250 }
moveToPosition
195 public final boolean moveToPosition(int position) {
196 // Make sure position is not past the end of the cursor
197 final int count = getCount();
198 if (position >= count) {
199 mPos = count;
200 return false;
201 }
202
203 // Make sure position isn't before the beginning of the cursor
204 if (position < 0) {
205 mPos = -1;
206 return false;
207 }
208
209 // Check for no-op moves, and skip the rest of the work for them
210 if (position == mPos) {
211 return true;
212 }
getCount()
Returns the current position of the cursor in the row set. The value is zero-based. When the row set is first returned the cursor will be at positon -1, which is before the first row. After the last row is returned another call to next() will leave the cursor past the last entry, at a position of count().
Returns:
the current cursor position.

Related

Given an array of Long values in Kotlin and a position parameter, when the position is in the middle of two of the array values, return the lowest

Spotify's lyrics API provides an Array of miliseconds to mark when the lyric line has changed. Having a Media Player that updates it's position every 50ms, how should i code in Kotlin the way to find the correct lyric line? The position param can be in the middle of two values of the array, so I want to get the lowest one of that two.
I tried to get the lowest value compared to the position parameter but lol, it will always be the first value of the Array... Silly fault of mine.
The problem is that I have a third one that indicates the range of that two value. For example: I have an Array of [45, 78, 125, 198]. If I pass the position param where it's value is 95, I want to return the 78 (that is the lowest value from itself, the position param and 125).
/** Input data for example (from your comment). */
val yourArray = arrayOf(45, 78, 125, 198)
val inputValue = 95
/** How to get needed index. */
val resultIndex = yourArray.indexOfLast { it < inputValue }.takeIf { it != -1 }
If you get resultIndex == null - it means you don't have value inside your array which lower then your inputValue.
I think it's simpler than find indexOfFirst and compare result later. And absolutely better and safer when sort() solution.
Insert the position param into the array, sort it, find its index and use it to get the closest value.
val array: MutableList<Long> = mutableListOf(4L, 9L, 5L, 1L)
val position = 7L
array.add(position)
println(array[array.sorted().indexOf(position) - 1])
Output: 5
If I correctly understand, you need simply use min function for compare two numbers in Kotlin and find the low one: link
Here’s a way to do it without having to make two copies of the list and doing a sort.
val foundIndex = lyricTimesList.indexOfFirst { it > inputTime }
val result = if (foundIndex == -1) lyricTimesList.size - 1 else foundIndex - 1
Note the result could be -1 if the input time is less than the first number in the list.

Cursor Index out o fBounds Exception :Index 11 requested, with a size of 11

I faced one issue randomly whenever try to get the getSelectedCustomerPhone() then randomly cursor index out of Bound Exception will appear.
Is there anything wrong with this code?. I could not find the bug.
private String getSelectedCustomerPhone() {
myCursor.moveToPosition(selectedCustPosition);
String phone =
myCursor.getString(myCursor.getColumnIndex("cust_phone"));
if (phone != null) return phone;
return "";
}
It seems that selectedCustPosition is outside of the cursor range [0, Cursor.getCount() - 1]. Try understanding why it happens.
As a workaround to prevent the crash, you can add a check
if (0 <= selectedCustPosition && selectedCustPosition < myCursor.getCount()) {
myCursor.moveToPosition(selectedCustPosition);
// ...
}
But this is only a workaround that will more likely return incorrect phone number. Better to understand the real problem: why selectedCustPosition is incorrect.

Using limit () and offset () in QueryBuilder (ANDROID , ORMLITE)

#SuppressWarnings("deprecation")
public List<Picture> returnLimitedList(int offset, int end) {
List<Picture> pictureList = new ArrayList<Picture>();
int startRow = offset;
int maxRows = end;
try {
QueryBuilder<Picture, Integer> queryBuilder = dao.queryBuilder();
queryBuilder.offset(startRow).limit(maxRows);
pictureList = dao.query(queryBuilder.prepare());
} catch (SQLException e) {
e.printStackTrace();
}
return pictureList;
}
I have a table of Pictures in the database, and must return a limited list, 20 lines at a time.
But when I use ex: QueryBuilder.offset(11).limit(30);
I can not return the list limited to 20 lines.
The list only comes to me with the limit.
It's as if the offset remain always with value 0
ex: (0 - 30)
Is there any other way to return a limited list for initial index and end index?
Could anyone help me?
This question was asked two months ago, but I'll answer if anyone stumbled on the same problem as I did.
There's misunderstanding about what offset means in this case, here follows what SQLite Documentations says about it
If an expression has an OFFSET clause, then the first M rows are omitted from the result set returned by the SELECT statement and the next N rows are returned, where M and N are the values that the OFFSET and LIMIT clauses evaluate to, respectively.
Source
Based on your query, you'll return 30 lines starting at the #11 line.
So the correct way is:
queryBuilder.offset(startRow).limit(20);
With limit being the number of rows that will return, not the ending row.
pictureList = dao.query(queryBuilder.prepare());
And the returned List with the first value starting on pictureList.get(0)
Edit: #Gray 's help on comments

ORMLite's createOrUpdate seems slow - what is normal speed?

Calling the ORMLite RuntimeExceptionDao's createOrUpdate(...) method in my app is very slow.
I have a very simple object (Item) with a 2 ints (one is the generatedId), a String and a double. I test the time it takes (roughly) to update the object in the database (a 100 times) with the code below. The log statement logs:
time to update 1 row 100 times: 3069
Why does it take 3 seconds to update an object 100 times, in a table with only 1 row. Is this the normal ORMLite speed? If not, what might be the problem?
RuntimeExceptionDao<Item, Integer> dao =
DatabaseManager.getInstance().getHelper().getReadingStateDao();
Item item = new Item();
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
item.setViewMode(i);
dao.createOrUpdate(item);
}
long update = System.currentTimeMillis();
Log.v(TAG, "time to update 1 row 100 times: " + (update - start));
If I create 100 new rows then the speed is even slower.
Note: I am already using ormlite_config.txt. It logs "Loaded configuration for class ...Item" so this is not the problem.
Thanks.
This may be the "expected" speed unfortunately. Make sure you are using ORMLite version 4.39 or higher. createOrUpdate(...) was using a more expensive method to test for existing of the object in the database beforehand. But I suspect this is going to be a minimal speed improvement.
If I create 100 new rows then the speed is even slower.
By default Sqlite is in auto-commit mode. One thing to try is to wrap your inserts (or your createOrUpdates) using the the ORMLite Dao.callBatchTasks(...) method.
In by BulkInsertsTest android unit test, the following doInserts(...) method inserts 1000 items. When I just call it:
doInserts(dao);
It takes 7.3 seconds in my emulator. If I call using the callBatchTasks(...) method which wraps a transactions around the call in Android Sqlite:
dao.callBatchTasks(new Callable<Void>() {
public Void call() throws Exception {
doInserts(dao);
return null;
}
});
It takes 1.6 seconds. The same performance can be had by using the dao.setSavePoint(...) method. This starts a transaction but is not as good as the callBachTasks(...) method because you have to make sure you close your own transaction:
DatabaseConnection conn = dao.startThreadConnection();
Savepoint savePoint = null;
try {
savePoint = conn.setSavePoint(null);
doInserts(dao);
} finally {
// commit at the end
conn.commit(savePoint);
dao.endThreadConnection(conn);
}
This also takes ~1.7 seconds.

Android Cursor - moveToNext() doesnt seem to go to end of cursor

Why doesnt my Android Cursor go all the way to the end of the original "promise"??
My cursor.getCount() differs from my last cursor.getPosition(). Check my while loop! It is all I do with it!
Notes:
1. it is about querying the Contacts content provider (android api >5)
2. I display only the esential code
Cursor cursor = mContext.getContentResolver().query(mUri, mProjections, null, null, null);
Logger.d(TAG, "*** cursor.getCount(): "+cursor.getCount());
while (cursor.moveToNext()) {
Logger.d(TAG, "| position: "+cursor.getPosition());
processMainCursor(serializer, cursor);
}
cursor.close();
processMainCursor() will display data from cursor + do another queries: one 4 phones, one 4 emails, one 4 IM accounts:
void processMainCursor(XmlSerializer serializer, Cursor main_cursor) {
writeCursorData(serializer, main_cursor); //writes cursor data, column by column
writePhoneEntities(serializer, main_cursor);
writeEmailEntities(serializer, main_cursor);
writeIMEntities(serializer, main_cursor);
}
In none of my writeXXX methods do i close my main_cursor or move next!!!..have to trust me on that.. i just do a new query, print data & close that cursor
So statistics:
cursor.getCount() = 695 (always)
commenting writePhoneEntities, writeEmailEntities, writeIMEntities: cursor.getCount() =
last cursor.getPosition() = 695 (so correct!)
leaving one/two/all of my writeXEntities shows randomness; example: leaving them all:
last cursor.getPosition() sometimes displays 254, 257, 253, etc; leaving just phone & IM: 514, 510, 511, etc (so different RUN -> different last cursor.getPosition() VALUE)
So oppinions.. Why is that? Is it memory related?
Update:
Leaving any of my writeXEntities displays at the end in logcat:
Removing dead content provider: contacts
Update 2
Adding cursor.moveToFirst(); & doing loop like
do {
//do whatever you want
} while (cursor.moveToNext());
didn't do the job..
So maybe the answer is in this logcat entries:
05-21 23:29:30.209: I/ActivityThread(7085): Removing dead content provider: contacts
05-21 23:29:30.209: I/ActivityThread(7085): Removing dead content provider: com.android.contacts
SAMPLE OF a writeXEntity REMOVED
SOLUTION .. i wasnt closing the cursors from writeXEntity corectly (probably leaving quite a lot of open cursor after main while)
in reality i was closing like this
if(phone_cursor!=null && phone_cursor.getCount() > 0)
{
//... stuff
phone_cursor.close();
}
i should have closed after if
if(phone_cursor!=null && phone_cursor.getCount() > 0)
{
//... stuff
}
phone_cursor.close();
I guess leaving a basilion cursor open ..was the answer?!?
You need to move the cursor to the first row. Try adding cur.moveToFirst() before the while loop.
You might also consider using a do-while loop. This will ensure that you never skip over the first row in the cursor:
if (cursor.moveToFirst()) {
do {
//do whatever you want
} while (cursor.moveToNext());
}
cursor.close();
Well, they won't be the same number as the getCount is the number of items, and the position is the position, ( the first one being 0). So the final position should always be one less than the count.
If it's something other than that, I guess I'm not understanding your question properly.
Use cursor as shown below:
if(cursor.getCount() == 0)
{
//No entry found
}
else {
cursor.moveToFirst();
do {
//do whatever you want
} while (cursor.moveToNext());
cursor.close();
After reading the answer you already found (problem with closing cursors) I think that the best way to ensure you close them all is with this code:
Cursor c = null;
try {
c = <your query>;
if (c.moveToFirst()) { // No point in doing more if empty.
do {
<process this cursor row>
} while (c.moveToNext());
}
}
finally {
if (c != null) c.close(); // Not sure the check needed, maybe if query was really wrong.
}

Categories

Resources