I'm new to Android Studio and this is my first application in general where I'm working with database connectivity, so I may just be fundamentally misunderstanding how the cursor works.
I'm querying my database, and tests show that the query is successful, specifically the getCount() method returns 2 as the number of rows the cursor object contains. However when I call the getString() method it throws an exception instead of returning the column data.
Anything pop out right away that could be wrong with this code?
public void GetFacts(View v) {
Cursor cursor = database.query(ExternalDbOpenHelper.TABLE_NAME,
null, "valueRange = 'MEDIUM'", null, null, null, null);
// Log number of rows from query
Log.d("CursorTest", "Row count: " + cursor.getCount());
try {
// get data from "factName" column of database
String columnName = cursor.getColumnName(0);
Log.d("CursorTest", "Column Name: " + columnName);
String data = cursor.getString(cursor.getColumnIndex(columnName));
} catch(Exception e) {
// Log exception thrown
Log.d("CursorTest", "Error getting data: " + e.getMessage());
}
}
And the log gives me the following:
D/CursorTest: Row count: 2
D/CursorTest: Column Name: factName
D/CursorTest: Error getting data: Index -1 requested, with a size of 2
Try to move the cursor to the first position first example
cursor.moveToPosition(0);
Your cursor initializes at index -1. You need to call moveToNext() or moveToPosition(int) to set it to a position with data in it.
Related
I am getting an error in Android Studio to do with my Cursor.
I have the following line in my code
String data = cursor.getString(cursor.getColumnIndex(columnIndex));
columnIndex is being passed into the method.
This part cursor.getColumnIndex(columnIndex) produces the following error
Value must be ≥ 0
Its happening in my DBHelper class and also my recycler adapter when it uses a cursor too.
It shows up as an error in red but the app still builds and runs without issue.
Any ideas?
Thanks for any help.
Update 22-Sep-21
I'm adding some code as requested and also how i have got around this error. Not sure if its the best way though.
So the method im using is this....
public String getTripInfo(String tableName, int tripNo, String columnIndex){
String data = "";
// Select all query
String selectQuery = "SELECT * FROM " + tableName + " WHERE " + TRIP_DETAILS_TRIP_NUMBER + "=" + tripNo;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// Looping through all rows and adding to list
if(cursor.moveToFirst()){
do{
data = cursor.getString(cursor.getColumnIndex(columnIndex));
} while(cursor.moveToNext());
}
// Closing connections
cursor.close();
db.close();
//Returning number plates
return data;
}
The error is in the do while loop. The part in red is "cursor.getColumnIndex(columnIndex))"
The way i have gotten around this error is using the following code instead
public String getTripInfo(String tableName, int tripNo, String columnIndex){
String data = "";
// Select all query
String selectQuery = "SELECT * FROM " + tableName + " WHERE " + TRIP_DETAILS_TRIP_NUMBER + "=" + tripNo;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// Looping through all rows and adding to list
if(cursor.moveToFirst()){
do{
int index = cursor.getColumnIndex(columnIndex);
data = cursor.getString(index);
} while(cursor.moveToNext());
}
// Closing connections
cursor.close();
db.close();
//Returning number plates
return data;
}
I had an error like this.
My solution : change method getColumnIndex into getColumnIndexOrThrow.
The problem is that cursor.getColumnIndex() can return -1, you're passing it as a direct parameter, and the cursor getters need a column index gte 0. The getters' parameter is annotated with #IntRange(from = 0) which is why lint marks it as an error.
So, even though you might have built your project such that it would never produce an invalid column index, the fact that such a possibly could exist is why lint is tagging it.
Your code revision only avoids the issue. It would be best to use cursor.getColumnIndexOrThrow() or test index for gte 0.
You can get away with your changes since you know more about your project than lint does, it just isn't the best practice.
Use This Method Proper Work :-
#SuppressLint("Range") Strong name = cursor.getString(cursor.getColumnIndex(indexNumber));
I have an android project, with a database where entries are logged as pairs with the same ID.
I have two for loops, one to get all entries of a certain ID, and one to get all entries in the table. These are then automatically populated into a listview.
The problem I have is that the program crashes when I attempt to use the forloop that gets all entries from the database, but it works perfectly fine when I use the for loop that wants all entries with the same ID. I have been commenting out the for loop im not using.
The for loops:
List<Assignment> list = db.getPickupDelivery(1);
for (int i = 0; i < list.size();i++)
{
allDeliveries.add(list.get(i));
}
List<Assignment> list = db.getAllAssignments();
for (int i = 0; i < list.size();i++)
{
allDeliveries.add(list.get(i));
}
The methods they call:
public List<Assignment> getPickupDelivery(int i) {
List<Assignment> assignments = new LinkedList<Assignment>();
//bygg query
String query = "SELECT * FROM " + TABLE_ASSIGNMENTS + " WHERE id = " + i;
//fa referens
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
//iterera och bygg och lagg till
Assignment assignment = null;
if (cursor.moveToFirst()) {
do {
assignment = new Assignment();
assignment.setID(Integer.parseInt(cursor.getString(0)));
assignment.setType(cursor.getString(1));
assignment.setSenderreceiver(cursor.getString(2));
assignment.setAdress(cursor.getString(3));
assignment.setTime(cursor.getString(4));
assignment.setZipcode(cursor.getString(5));
assignment.setContact(cursor.getString(6));
assignment.setPhone(cursor.getString(7));
assignment.setInstructions(cursor.getString(8));
//lagg till
assignments.add(assignment);
} while (cursor.moveToNext());
}
cursor.close();
Log.d("getPickupDelivery()", assignments.toString());
return assignments;
}
public List<Assignment> getAllAssignments() {
List<Assignment> assignments = new LinkedList<Assignment>();
//bygg query
String query = "SELECT * FROM " + TABLE_ASSIGNMENTS;
//fa referens
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
//iterera och bygg och lagg till
Assignment assignment = null;
if (cursor.moveToFirst()) {
do {
assignment = new Assignment();
assignment.setID(Integer.parseInt(cursor.getString(0)));
assignment.setType(cursor.getString(1));
assignment.setSenderreceiver(cursor.getString(2));
assignment.setAdress(cursor.getString(3));
assignment.setTime(cursor.getString(4));
assignment.setZipcode(cursor.getString(5));
assignment.setContact(cursor.getString(6));
assignment.setPhone(cursor.getString(7));
assignment.setInstructions(cursor.getString(8));
//lagg till
assignments.add(assignment);
} while (cursor.moveToNext());
}
cursor.close();
Log.d("getAllAssignments()", assignments.toString());
return assignments;
}
The error I get at the time of the crash is a an error that says "...MainActivity}: java.lang.NumberFormatException: Invalid int: "null""
My guess is that in your database definition, you didn't specify the ID column as INTEGER NOT NULL. So when you select every row, one or more of those rows has a null ID, which you're trying to parse as an int here:
assignment.setID(Integer.parseInt(cursor.getString(0)));
Change your database definition to require that the ID column is not null. You'll need to uninstall or clear data on your app so the database is recreated.
Also another tip - Android's SQLITE implementation will enforce that you have a column called "_id", so I'd suggest using that, not "id". Otherwise you'll end up with an extra column you don't need.
In your code:
assignment.setID(Integer.parseInt(cursor.getString(0)));
if cursor.getString(0) returns null, then Integer.parseInt(String str) will throw NumberFormatException.
Check this line or you can use try-catch and print the appropriate message in catch if you'll get NumberFormatException.
The exception is the hint. It says that a string null is being parsed as a number and this fails.
In your code there the place where it happens is:
assignment.setID(Integer.parseInt(cursor.getString(0)));
First you get a string from the cursor and then you pass it to Integer.parseInt for parsing.
So the cause of the problem is that you expect there to be no null values in the first column but there is at least one.
Also, your code is unnecessarily complex and inefficient. Instead of Integer.parseInt(cursor.getString(0)) you could write cursor.getInt(0) to directly get an int. This is also likely to throw an error on the null value though (but the error message might be more informative).
im trying to get all the elements of a row in sqlite by ID using a cursor. The cursor is not null, but i can't seem to operate with the cursor, Here is my code:
public Book getBookByid (int itemId) {
String selectQuery = "SELECT * FROM " + tables[0] + " WHERE " + SQLiteHelper.ITEM_ID + " = " + itemId;
Cursor cursor = database.rawQuery(selectQuery, null);
Book bookRead = new Book();
if(cursor!=null) {
Log.i("myApp","cursor not null");
if (cursor.moveToFirst()) {
Log.i("myApp","title" + cursor.getColumnIndex(arrayFields.get(0)[1]));
bookRead.setTitle(cursor.getString(cursor.getColumnIndex(arrayFields.get(0)[1])));
bookRead.setGenre(cursor.getString(cursor.getColumnIndex(arrayFields.get(0)[2])));
bookRead.setDescription(cursor.getString(cursor.getColumnIndex(arrayFields.get(0)[3])));
bookRead.setRecommendation(cursor.getString(cursor.getColumnIndex(arrayFields.get(0)[4])));
bookRead.setPhoto(cursor.getString(cursor.getColumnIndex(arrayFields.get(0)[5])));
bookRead.setLike(cursor.getInt(cursor.getColumnIndex(arrayFields.get(0)[6])));
}
Log.i("myApp","title" + bookRead.getTitle());
}
cursor.close();
return bookRead;
}
The problem is that the code does not enter the if(cursor.moveToFirst()) so i cannot assing the values to my object, getting a null object reference.
My logs show the following:
05-13 09:37:23.720 13918-13918/com.appforbrands.meloapunto I/myApp﹕ cursor not null
05-13 09:37:23.720 13918-13918/com.appforbrands.meloapunto I/myApp﹕ titlenull
I'm also getting a blue warning or error in logcat:
05-13 10:04:14.555 3969-3969/com.appforbrands.meloapunto W/Bundle﹕ Key itemId expected Integer but value was a java.lang.Long. The default value 0 was returned.
05-13 10:04:14.559 3969-3969/com.appforbrands.meloapunto W/Bundle﹕ Attempt to cast generated internal exception:
This is steps you need to do to debug your function:
Make sure you have valid database connection.
Check and make sure your raw query are correct.
The itemID is exist in your data.
Sqlite may be confused finding your id in your Sqlite book table, so the query can't find any row. Check your table definitions or manually write the table id in your query String.
I am just trying to search for the data in multiple table.If the where condition data is not present in first table(tab1) then it has to search in the second table(tab2) but I am getting the exception showing that
Cursor Index Out of Bounds Exception: Index -1 requested with size 0
Here is my code
SQLiteDatabase db=openOrCreateDatabase("train",SQLiteDatabase.CREATE_IF_NECESSARY, null);
Cursor c1;
String[] table={"tab1","tab2","tab3","tab4"};
int i=0;
do {
c1 = db.rawQuery("select * from '"+table[i]+"' where name='Triplicane'", null);
i++;
} while(c1 == null);
int id1=c1.getInt(0);
String nam1=c1.getString(1);
Toast.makeText(fare.this,"ID no:"+id1, Toast.LENGTH_LONG).show();
Toast.makeText(fare.this,"name"+nam1, Toast.LENGTH_LONG).show();
So from the beginning. Implicitly, each Cursor is positioned before first row so if you want to work with it you need to call
cursor.moveToFirst()
that moves Cursor to first row if is not empty and then is ready for work. If Cursor is empty simply it returns false. So how i mentioned now this method is very handy indicator whether your Cursor is valid or not.
And as my recommendation i suggest you to change your code because i think is broken and it sounds like "spaghetti code"
Cursor c = null;
String[] tables = {"tab1", "tab2", "tab3", "tab4"};
for (String table: tables) {
String query = "select * from '" + table + "' where name = 'Triplicane'";
c = db.rawQuery(query, null);
if (c != null) {
if (c.moveToFirst()) { // if Cursor is not empty
int id = c.getInt(0);
String name = c.getString(1);
Toast.makeText(fare.this, "ID: " + id, Toast.LENGTH_LONG).show();
Toast.makeText(fare.this, "Name: " + name, Toast.LENGTH_LONG).show();
}
else {
// Cursor is empty
}
}
else {
// Cursor is null
}
}
Notes:
Now i want to tell you some suggestions:
An usage of parametrized statements is very good practise so in a
future if you will work with statements, use placeholders in them. Then your statements becomes more human-readable, safer(SQL Injection) and faster.
It's also a very good practise to create static final fields that will hold
your column names, table names etc. and to use
getColumnIndex(<columnName>) method to avoid "typo errors" which are looking for very bad.
Your Cursor flag to empty row , On Sqlite cursor pointed to row number -1 ,
then if you use c.moveNext() or c.moveToFirst() you'll be able to read rows "row by row "
write cursor.movetoFirst() before getting data from cursor.
I have an application that runs fine on android 2.1, but when trying to transition it to 3.0 I get a cursor error that I'm not familar with.
Java.lang.IllegalStateException: Couldn't read row0, column -1 from
cursor window. Make sure cursor is initialized correctly before
accessing data from it.
All the data is storred in a SQLite database and this code works fine in android 2.1. Does a cursor have to be initialized differently in android 3.0?
Listed below is my code.
private void OpenGroupData(){
SQLiteDatabase db = openOrCreateDatabase(DATABASE_NAME,Context.MODE_PRIVATE,null);
Cursor cur = db.rawQuery("SELECT groupid FROM properties GROUP BY GroupID" + ";" , null);
LinearLayout glayout = (LinearLayout) findViewById(R.id.Grouplayout);
LinearLayout gwindow = (LinearLayout) findViewById(R.id.groupwindow);
TextView data = new TextView(this);
glayout.addView(data);
data.setText("");
int ID = cur.getColumnIndex("groupid");
int idvalue;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
try{
// Check if our result was valid.
cur.moveToFirst();
if (cur != null) {
// Loop through all Results
do {data = new TextView(this);
data.setTextSize(20);
data.setClickable(true);
data.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
GroupClick(v);
}
});
glayout.addView(data);
idvalue = cur.getInt(ID);
data.setId(idvalue);
data.setText("Group: " + idvalue);
}while(cur.moveToNext());
}
cur.close();
db.close();
} catch(Exception e) {
Toast.makeText(getApplicationContext(), "Open Group Exception: " + e.toString(), Toast.LENGTH_SHORT).show();
}
}
I ran into the same error message earlier this day. All it turned out to was that I made a typo in the column name. So, if it still applies, you could go and check the column name for typo's. Note that its case sensitive aswell. Error for me was along the lines of:
//Trew error
c.getColumnIndex("ArticleNumber");
//Was correct
c.getColumnIndex("Articlenumber");
Alright I figured it out. For some reason when trying to transistion my application to 3.0 when my cursor goes and gets the column index for a field, in this case ("groupid") it is returning a value of -1. When the Cursor tries to start at -1 it crashes because it can't find a record at row(0), column(-1). So my fix was to just add one to the column index when getting the id. see below.
int ID = cur.getColumnIndex("groupid") + 1;
int idvalue;
By adding 1 to the Column index it seems to have solved the problem.
If getColumnIndex returns -1, then the column doesn't exist.
Otherwize it returnes zero-based column index.
-1 is the _id column which every sqlite table should have as is required by the android framework. If you have to add +1 to the index you are going wrong somewhere.
The -1 value returns form getColumnIndex(columnName) if 'columnName' can't be found. Check the column names