My cursor is crashing my application with the android database error.
CursorIndexOutOfBoundsException: Index -1 requested, with a size of 1
I made another much less optimized slider that scans my database and I find the good value.
public Cursor getAllDataTableStaffDatabase(String table_name){
this.open();
Cursor result =this.mDb.rawQuery("SELECT * FROM " + table_name,null);
return result;// fonctionne très bien
}
public String findNameOfStaffBymail(String mail) {
String sql = " SELECT * FROM " + DatabaseStaffHandler.STAFF_TABLE_NAME + " WHERE " + DatabaseStaffHandler.STAFF_MAIL + " = ? ";
Cursor result = super.mDb.rawQuery(sql, new String[]{mail});
Cursor data = super.getAllDataTableStaffDatabase(DatabaseStaffHandler.STAFF_TABLE_NAME);
String test = result.getString(1); //error
while (data.moveToNext()) {
if (data.getString(3).equals(mail)) {
viewAll();
return data.getString(1);
}
}
}
I would like to retrieve the value name that corresponds to the email address.
This usually happens when you do not have the data in your Cursor and you are still trying to access the data. It is similar to the ArrayIndexOutOfBoundsException. I found nothing wrong with your query so far. However, I think you might consider adding null checking in your code which will prevent your application from crashing. Especially in the while loop, you need to put a null check in the condition.
And you need to use the moveToFirst function wherever necessary.
public Cursor getAllDataTableStaffDatabase(String table_name) {
this.open();
Cursor result = this.mDb.rawQuery("SELECT * FROM " + table_name,null);
return result;
}
public String findNameOfStaffBymail(String mail) {
String sql = " SELECT * FROM " + DatabaseStaffHandler.STAFF_TABLE_NAME + " WHERE " + DatabaseStaffHandler.STAFF_MAIL + " = ? ";
Cursor result = super.mDb.rawQuery(sql, new String[]{mail});
Cursor data = super.getAllDataTableStaffDatabase(DatabaseStaffHandler.STAFF_TABLE_NAME);
// Add a null checking here.
if (result != null) {
result.moveToFirst();
String test = result.getString(1);
}
if(data != null) data.moveToFirst();
while (data != null) {
if (data.getString(3).equals(mail)) {
viewAll();
return data.getString(1);
}
data.moveToNext();
}
}
Hope that solves your problem.
Thank you for your reply. I found my problem thanks to you. I wonder if the cursor does not boot at the end. But it is good practice to check if received is not null. Thank you and have a nice day
Related
I'm getting spurious errors when trying to doInBackground of an AsyncTask which I initiate in MainActivity when the user clicks btnSearch.
Here's the part of doInBackground where I might get no error, might get error after 1 transaction, might get error at record 23001 after 23 transactions. I got returnCode < 0 after trying to insertWord.
private class LoadDatabase extends AsyncTask<Object, Integer, Void
{
protected Void doInBackground(Object[] params)
{
...
my_openDb("DatabaseConnector.LoadDatabase.doInBackground");
while(scDict.hasNext())
{
int kTransactions = 0;
try
{
mDatabase.beginTransaction();
while(kTransactions < MAX_TRANSACTIONS && scDict.hasNext())
{
s = scDict.next();
count++;
long returnCode = insertWord(s); // error here **********
if(returnCode < 0)
{
if(debug) Log.w("`````Abort--can't add <",s + "> at " + count + " with RC = " + returnCode + " and KT = " + kTransactions );
my_closeDb("DatabaseConnector.LoadDatabase.doInBackground DISASTER");//$$
System.exit(0);
}
++ kTransactions;
}
mDatabase.setTransactionSuccessful();
}
catch(Exception e){ Log.w("`````", "Exception " + e.toString()); }
finally
{
mDatabase.endTransaction();
publishProgress((Integer) (int) s.charAt(0));
}
}
my_closeDb("doInBackground outer while ended");
Method insertWord:
long insertWord(String _word)
{
long r = -1;
ContentValues newWord = new ContentValues();
newWord.put(WORD_COLUMN_NAME, _word);
try {
// r = mDatabase.insert (TABLE_NAME,null,newWord);
r = mDatabase.insertWithOnConflict(TABLE_NAME,null,newWord,SQLiteDatabase.CONFLICT_REPLACE);
return r;
} catch (Exception e) {
if(debug)Log.w("DBC", "insert failed for <" + _word + ">");
if(debug)Log.w("DBC", "exception " + e.toString());
my_closeDb(DatabaseConnector.insertWord");
}
return -1 ; // -1 if can't insert
}
The commented out line always worked in the past, until major overhaul to simplify code. (GREAT idea.)(NOT!) I got the idea of insertWithOnConflict from https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html where they say insertWithOnConflict is the General method for inserting a row into the database.
Of course I got insert from a text book. AS says it's a convenience method for inserting a row into the database. But it does lack the algorithm for resolving conflicts. There shouldn't be any conflicts. I made the change to insertWithOnConflict when I got errors with insert.
That was probably my first warning that I was on thin ice.
I call DatabaseConnector from MainActivity, which calls inner classes: DatabaseHelper, which calls LoadDatabase and then doInBackground.
I'm not sure I should have an AsyncTask so directly connected to MainActivity because of Answers and comments suggesting concurrence issues might be a problem.
Another suggestion was to put the AsyncTask inside MainActivity. That would mean I'd have to move classes DatabaseConnector and its inner classes there, too. If it all seems overly-complicated, I just followed the big example in a textbook. But you must connect the database to the activity, and you do need help, and if the task MUST run in the background, so it must be AsyncTask, as I understand it.
Call from MainActivity:
dbc = new DatabaseConnector(MainActivity.this, getAssets(), databaseFileExists());
In DatabaseConnector:
public DatabaseConnector(Context _context, AssetManager _assets, boolean dbExists)
{
mContext = _context;
mDbOpenHelper = new DbOpenHelper(_context, DATABASE_NAME, null, 1);
SQLiteDatabase db = mDbOpenHelper.getWritableDatabase();
if( ! dbExists)
createAndOrFillDb(db);
}
createAndOrFillDb:
void createAndOrFillDb(SQLiteDatabase db)
{
...
db.execSQL("CREATE TABLE " + TABLE_NAME + "(" + WORD_COLUMN_NAME + " TEXT primary key );")
//...
cursor = db.query(TABLE_NAME, mColumns, null, null, null, null, WORD_COLUMN_NAME);
//...
LoadDatabase
__loadDb;
__loadDb = new LoadDatabase();
__loadDb.execute((Object[]) null);
}
So my questions are
(1) Do you think I'm getting spurious results during transactions in doInBackground because of it being in a class separate from MainActivity and if so, what can I do about it?
(2) Do you think I should just stick 1200 lines of code into MainActivity, resulting in a 2200-line monster so I won't have to worry about concurrency?
(3) Maybe initiate doInBackground from a thread separate from UI? (No clue how to control that, but I'm willing to try.)
(4) What else might you suggest?
I am developing a simple social media for my case study. I was able to retrieve the post from the people the user follows. Here's the screenshot:
As you can see, the problem is that the posts were not sorted according to date/id. Instead, it is sorted according to the people the user follows. It is because I am only merging the cursors using mergecursor. Here's a part of my code:
ListView listviewFeed = (ListView) findViewById(R.id.listviewFeed);
Cursor cursorFeed = DataAdapters.getFeed(dbHelper, strUserID);
//This code is for retrieving user's own posts
Cursor cursorFollowing = DataAdapters.getFollowing(dbHelper,strUserID);
//This code is for retrieving the followed users.
if(cursorFollowing.getCount()>0) {
for (int intCtr = 0; intCtr < cursorFollowing.getCount(); intCtr++) {
int intUseridI = cursorFollowing.getColumnIndex(Tables.FollowTable.COLUMN_USERID);
String strUseridI = cursorFollowing.getString(intUseridI);
Cursor cursorFollowingFeed = DataAdapters.getFeed(dbHelper, strUseridI);
\\This code is for retrieving the posts of the people the user follows.
if(intCtr>0)
{
mergeCursor = new MergeCursor(new Cursor[]{mergeCursor, cursorFollowingFeed});
}else {
mergeCursor = new MergeCursor(new Cursor[]{cursorFeed, cursorFollowingFeed});
}
//This code is for merging the cursors.
if (intCtr + 1 == cursorFollowing.getCount()) {
cursorFollowing.close();
} else {
cursorFollowing.moveToNext();
}
}
ListViewAdapterMeasurement adapterMeasurement = new ListViewAdapterMeasurement(this, mergeCursor);
listviewFeed.setAdapter(adapterMeasurement);
}else
{
ListViewAdapterMeasurement adapterMeasurement = new ListViewAdapterMeasurement(this, cursorFeed);
listviewFeed.setAdapter(adapterMeasurement);
}
It is all working well. I just want to order the posts by Date or by ID.
Is there any way to sort MergeCursor?
I guess there is no way to sort the MergeCursor so I tried to think of other ways.
I changed my query like this:
public static Cursor getFeed (DBHelper dbHelper, String strUserID)
{
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursorFollowing = getFollowing(dbHelper,strUserID);
String strQuery = "SELECT * FROM feed_tbl WHERE "+ Tables.FeedTable.COLUMN_USERID + "="+strUserID;
if(cursorFollowing.getCount()>0)
{
for(int intCtr=0;intCtr<cursorFollowing.getCount();intCtr++)
{
int intUseridI = cursorFollowing.getColumnIndex(Tables.FollowTable.COLUMN_USERID);
String strUseridI = cursorFollowing.getString(intUseridI);
String strConcatQuery = " OR "+ Tables.FeedTable.COLUMN_USERID + "="+strUseridI;
if (intCtr + 1 == cursorFollowing.getCount()) {
cursorFollowing.close();
} else {
cursorFollowing.moveToNext();
}
strQuery = strQuery +""+strConcatQuery;
Log.v(TAG,strQuery);
}
}
Cursor cursor = db.rawQuery(strQuery+" ORDER BY "+ Tables.FeedTable.COLUMN_ID + " DESC",null);
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
}
The result on the log tag is this:
V/FeedMe: SELECT * FROM feed_tbl WHERE feed_userid=1 OR feed_userid=2 OR feed_userid=4 OR feed_userid=5
Just to make things clear to those who have the same problem with me which is about MergeCursor sorting. THERE IS NO SUCH WAY TO SORT MERGECURSOR :)
Thankyou!
I have a piece of JAVA code that is accessed by multiple threads.
synchronized (this.getClass())
{
System.out.println("stsrt");
certRequest.setRequestNbr(
generateRequestNumber(
certInsuranceRequestAddRq.getAccountInfo().getAccountNumberId()));
System.out.println("outside funcvtion"+certRequest.getRequestNbr());
reqId = Utils.getUniqueId();
certRequest.setRequestId(reqId);
System.out.println(reqId);
ItemIdInfo itemIdInfo = new ItemIdInfo();
itemIdInfo.setInsurerId(certRequest.getRequestId());
certRequest.setItemIdInfo(itemIdInfo);
dao.insert(certRequest);
addAccountRel();
System.out.println("end");
}
the function generateRequestNumber() generates a request number based on the data fetched from two database tables.
public String generateRequestNumber(String accNumber) throws Exception
{
String requestNumber = null;
if (accNumber != null)
{
String SQL_QUERY = "select CERTREQUEST.requestNbr from CertRequest as CERTREQUEST, "
+ "CertActObjRel as certActObjRel where certActObjRel.certificateObjkeyId=CERTREQUEST.requestId "
+ " and certActObjRel.certObjTypeCd=:certObjTypeCd "
+ " and certActObjRel.certAccountId=:accNumber ";
String[] parameterNames = { "certObjTypeCd", "accNumber" };
Object[] parameterVaues = new Object[]
{
Constants.REQUEST_RELATION_CODE, accNumber
};
List<?> resultSet = dao.executeNamedQuery(SQL_QUERY,
parameterNames, parameterVaues);
// List<?> resultSet = dao.retrieveTableData(SQL_QUERY);
if (resultSet != null && resultSet.size() > 0) {
requestNumber = (String) resultSet.get(0);
}
int maxRequestNumber = -1;
if (requestNumber != null && requestNumber.length() > 0) {
maxRequestNumber = maxValue(resultSet.toArray());
requestNumber = Integer.toString(maxRequestNumber + 1);
} else {
requestNumber = Integer.toString(1);
}
System.out.println("inside function request number"+requestNumber);
return requestNumber;
}
return null;
}
The tables CertRequest and CertActObjRel used in generateRequestNumber() are updated by the functions "dao.insert(certRequest);" and "addAccountRel();" used in my initial code respectively. Also the System.out.println() statements used in my initial code have following output.
stsrt
inside function request number73
outside funcvtion73
A1664886-5F84-45A9-AB5F-C69768B83EAD
end
stsrt
inside function request number73
outside funcvtion73
44DAD872-6A1D-4524-8A32-15741FAC0CA9
end
If you notice both the threads run in a synchronized manner, but when the request number is generated , it's the same. My assumption is the database updation for CertRequest and CertActObjRel is done when both the threads finish their execution.
Could anyone help me to fix this?
I need to implement an algorithm that access to the database to check the last elemnt in order to calculate the new one. Of course, the first time it would be impossible because the database is empty and I get
IndexOutOfBoundsException) index 0 requested with a size of 0
To avoid it, I tried to check if cursor.getCount==0, and then I introduce a default first element. The problem is that, even when I have stored it in the database, cursor.getCount keeps being 0. Here is the code of my method:
public Measures getLastMeasure(String date) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_MEASURES, new String[] { KEY_ID,
KEY_DATE, KEY_TIME_HOUR, KEY_TIME_MINUTE, KEY_BE_INTAKE,
KEY_GLUCOSE, KEY_BOLUS, KEY_BASAL }, KEY_DATE + "=?",
new String[] { date }, null, null, KEY_TIME_HOUR + " DESC, "
+ KEY_TIME_MINUTE + " DESC", "1");
if (cursor.getCount() == 0) {
Measures m = new Measures("nodate", 0, 0, 0, 0, 0, 0);
return m;
} else {
if (cursor != null)
cursor.moveToFirst();
Measures m = new Measures(Long.parseLong(cursor.getString(0)), // id
cursor.getString(1), // date
Integer.parseInt(cursor.getString(2)), // timeHour
Integer.parseInt(cursor.getString(3)), // timeMinute
Double.parseDouble(cursor.getString(4)), // BE intake
Double.parseDouble(cursor.getString(5)), // glucose
Double.parseDouble(cursor.getString(6)), // bolus
Double.parseDouble(cursor.getString(7)) // basal
);
// return m
return m;
}
}
I hope you can help me. Thanks in advance to everyone.
I could be missing something, but that code looks correct to me. Are you certain that the data you're looking for is actually in the database and that the argument you're passing to getLastMeasure() is correct?
Looks like your query returns no data matching your search. If you only want latest data by date, I suggest order by KEY_DATE desc and limit 1, or max(KEY_DATE) instead of KEY_DATE + "=?"
Side note: no need to check if cursor is null (SQLiteDatabase#query never returns a null Cursor), and anyway your check is useless because you're accessing cursor even if it's null. Also you're not closing the Cursor.
I am trying to make custom search suggestions in my app. I’ve started from documentation and Searchable dictionary example. However, this example isn’t so good for me so I’ve started with some tests to find out exactly how to make it, because there is not much tutorials in the Internet also.
Generally my app has right now 2 databases – one normal and second with less number of columns – FTS3. What I would like to achieve is to connect suggestions provider to this FTS3 table.
What I was trying to do was to now was, using simple function, return in suggestions whole DB (around 200 records) after typing any letter in search box. I know about limit 50 records, but I don’t think it is the problem.
This are fragments from Provider’s code. What I found out, that when you type in text, provider goes to option SEARCH_SUGGEST:
// UriMatcher stuff
private static final int SEARCH_WORDS = 0;
private static final int GET_WORD = 1;
private static final int SEARCH_SUGGEST = 2;
private static final int REFRESH_SHORTCUT = 3;
private static final UriMatcher mUriMatcher = buildUriMatcher();
/**
* Builds up a UriMatcher for search suggestion and shortcut refresh queries.
*/
private static UriMatcher buildUriMatcher() {
Log.d(TAG,"urimatcher");
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
// to get definitions...
matcher.addURI(AUTHORITY, "mydb", SEARCH_WORDS);
matcher.addURI(AUTHORITY, "mydb/#", GET_WORD);
// to get suggestions...
matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST);
return matcher;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
switch (mUriMatcher.match(uri)) {
case SEARCH_SUGGEST:
Log.d(TAG,"SEARCH_SUGGEST");
if (selectionArgs == null) {
throw new IllegalArgumentException(
"selectionArgs must be provided for the Uri: " + uri);
}
return getSuggestions(selectionArgs[0]);
case SEARCH_WORDS:
Log.d(TAG,"SEARCH_WORDS");
if (selectionArgs == null) {
throw new IllegalArgumentException(
"selectionArgs must be provided for the Uri: " + uri);
}
return search(selectionArgs[0]);
case GET_WORD:
Log.d(TAG,"GET_WORD");
return null;
default:
Log.d(TAG,"default");
throw new IllegalArgumentException("Unknown Uri: " + uri);
}
}
private Cursor getSuggestions(String query) {
String[] columns = { MyDBAdapter.KEY_TITLE,MyDBAdapter.KEY_ID};
Log.d(TAG,"query1: " + query);
try{
Cursor tmp = MyDB.getAllEntriesFTS(false, columns,
null, null, null, null, MyDBAdapter.KEY_TITLE, null, query);
Log.d(TAG,"cursor: " + Integer.toString(tmp.getCount()));
}
catch(Exception e)
{
Log.d(TAG,e.toString());
}
return tmp;
}
In getSuggestions I put code that should generally work, but it doesn’t. Doesn’t work only when used here. When I used it in other activity to get cursor for listview everything was fine. Here it returns my NullPointerException.
So getting deeper I put also some Log tags in getAllEntriesFTS method and this method looks like this:
public Cursor getAllEntriesFTS(boolean distinct, String[] result_columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit, String query) {
Log.d(TAG,"query db: " + query);
String[] columns = { MyDBAdapter.KEY_TITLE, MyDBAdapter.KEY_ID};
Log.d(TAG,"columns: " + Integer.toString(result_columns.length));
Cursor allRows = null;
try{
allRows = db.query(distinct, DATABASE_TABLE_FTS, columns,
null, null, null, null, MyDBAdapter.KEY_TITLE, null);
Log.d(TAG,"OK");
}
catch(Exception e)
{
Log.d(TAG, e.toString());//it always goes there with NullPointerExceptionwhen used in provider
}
Log.d(TAG,Integer.toString(allRows.getCount()));
return allRows;
}
So, generalny speaking it should return cursor to whole DB, but instead it throws In place where it shouldn’t NullPointerException.
Can someone please tell me what am I doing wrong and how it should be done?
Thank's to JB Nizet I was able to find my mistake. I was thinking I've studied Google's example good, but I was wrong.
The problem was lack of database open before cursor call. It should look like this:
private Cursor getSuggestions(String query) {
String[] columns = { MyDBAdapter.KEY_TITLE,MyDBAdapter.KEY_ID};
Log.d(TAG,"query1: " + query);
try{
MyDB.open();
Cursor tmp = MyDB.getAllEntriesFTS(false, columns,
null, null, null, null, MyDBAdapter.KEY_TITLE, null, query);
MyDB.close();
Log.d(TAG,"cursor: " + Integer.toString(tmp.getCount()));
}
catch(Exception e)
{
Log.d(TAG,e.toString());
}
return tmp;
}
Thank you all for showing me it.