Reputation: 681
I'm a bit lost on this one. How can I get an OutOfBounds? Is there a size limit (besides sizeof (int))?
Maybe because multiple threads can come here? The UI thread and a Service thread?
java.lang.ArrayIndexOutOfBoundsException at kenyu73.realsignal.DatabaseWrapper.getSignalValues(DatabaseWrapper.java:137) at kenyu73.realsignal.DatabaseWrapper.getSignalValues(DatabaseWrapper.java:116) at kenyu73.realsignal.BarScaleGraph$buildGraphThread.drawGraph(BarScaleGraph.java:128) at kenyu73.realsignal.BarScaleGraph$buildGraphThread.execute(BarScaleGraph.java:94) at kenyu73.realsignal.BarScaleGraph$buildGraphThread.run(BarScaleGraph.java:74)
Also, I'm calling this classes methods with a static instance. I'm thinking threads are competing for the same variables??? Thoughts?
BarScaleGraph class
ContentValues[] values = DatabaseWrapper.getInstance().getSignalValues(getContentResolver(), signal_type, false);
DatabaseWrapper class
private static final DatabaseWrapper instance = new DatabaseWrapper();
// grab static instance so we only have one db wrapper
public static DatabaseWrapper getInstance() {
return instance;
}
. . . .
public ContentValues[] getSignalValues(ContentResolver cr, int signal_type_id, boolean bGroupByLatLon) {
String sWhere = "signal_type_id=" + signal_type_id;
Cursor cursor;
if (bGroupByLatLon) {
cursor = cr.query(CONSTS.CONTENT_URI_GRP_LATLNG, null, sWhere, null, null);
} else {
cursor = cr.query(CONSTS.CONTENT_URI_LOGGER, null, sWhere, null, null);
}
ContentValues[] values = new ContentValues[cursor.getCount()];
int count = 0;
if (cursor.getCount() > 0) {
cursor.moveToFirst();
do {
values[count] = new ContentValues(); // <--- LINE 137
values[count].put("signal_value", cursor.getInt(cursor.getColumnIndex("signal_value")));
values[count].put("latitude", cursor.getInt(cursor.getColumnIndex("latitude")));
values[count].put("longitude", cursor.getInt(cursor.getColumnIndex("longitude")));
values[count].put("timestamp", cursor.getLong(cursor.getColumnIndex("timestamp")));
values[count].put("network", cursor.getString(cursor.getColumnIndex("network")));
count++;
} while (cursor.moveToNext());
}
cursor.close();
return values;
}
EDIT: Going to try this - add synchronized to the instance
// grab static instance so we only have one db wrapper
public static synchronized DatabaseWrapper getInstance() {
return instance;
}
Upvotes: 1
Views: 327
Reputation: 10266
I would guess this is a race condition, where the count is change between threads... try to synchronize the method:
public synchronized ContentValues[] getSignalValues(...){
...
}
If the previous does not fit you, there is always this:
public ContentValues[] method1(...){
synchronized (monitor1) {
...
}
}
public ContentValues[] method2(...){
synchronized (monitor2) {
...
}
}
This would solve the issue, but I would try to prevented this sort of methodology using different architecture.
Upvotes: 1
Reputation: 1073978
The only reasonable answer is that cursor.getCount()
is returning a number lower than the number of loops that your do..while
loop makes. I'm not seeing an error in the logic of your do..while
loop (though it's unusual logic; see below).
My guess would be that it's a live cursor, and something else is deleting adding relevant rows while your loop is running. The only real way to find out will be to add instrumentation to the code so you can see what cursor.getCount()
returned, what count
was at the beginning of each loop iteration, etc.
If you don't really care why and just want it to stop happening, you could use a List
instead:
public ContentValues[] getSignalValues(ContentResolver cr, int signal_type_id, boolean bGroupByLatLon) {
String sWhere = "signal_type_id=" + signal_type_id;
Cursor cursor;
if (bGroupByLatLon) {
cursor = cr.query(CONSTS.CONTENT_URI_GRP_LATLNG, null, sWhere, null, null);
} else {
cursor = cr.query(CONSTS.CONTENT_URI_LOGGER, null, sWhere, null, null);
}
List<ContentValues> values = new LinkedList<ContentValues>();
ContentValues entry;
while (cursor.moveToNext()) {
entry = new ContentValues();
entry.put("signal_value", cursor.getInt(cursor.getColumnIndex("signal_value")));
entry.put("latitude", cursor.getInt(cursor.getColumnIndex("latitude")));
entry.put("longitude", cursor.getInt(cursor.getColumnIndex("longitude")));
entry.put("timestamp", cursor.getLong(cursor.getColumnIndex("timestamp")));
entry.put("network", cursor.getString(cursor.getColumnIndex("network")));
values.add(entry);
}
cursor.close();
return values.toArray(new ContentValues[values.size()]);
}
(Or code to that effect.)
There I've used a temporary linked list so I don't care what cursor.getCount
returns, converting it into an array when we're done. I've also used the more common idiom for looping cursors (since cursors start out just before the first row, while (cursor.moveToNext())
is a handy way to loop), not (again) that I saw a logic fault in your do..while
, but I like the simplicity and directness of while (cursor.moveToNext())
.
Upvotes: 2
Reputation: 109237
What about this,
int count = 0;
if (cursor.getCount() > 0) {
ContentValues[] values = new ContentValues[cursor.getCount()];
cursor.moveToFirst();
do {
if(cursor.getCount() >= count)
{
values[count].put("signal_value", cursor.getInt(cursor.getColumnIndex("signal_value")));
values[count].put("latitude", cursor.getInt(cursor.getColumnIndex("latitude")));
values[count].put("longitude", cursor.getInt(cursor.getColumnIndex("longitude")));
values[count].put("timestamp", cursor.getLong(cursor.getColumnIndex("timestamp")));
values[count].put("network", cursor.getString(cursor.getColumnIndex("network")));
}
count++;
} while (cursor.moveToNext());
}
cursor.close();
Upvotes: 0
Reputation: 4989
cursor.moveToFirst could be returning false. Try wrapping that in an if statement:
if (cursor.moveToFirst()) {
do....
}
Upvotes: 0
Reputation: 137272
While I'm not sure what the problem is, you can do it in a safer way:
List<ContentValues> values = new ArrayList<ContentValues>();
if (cursor.getCount() > 0) {
cursor.moveToFirst();
do {
ContentValues value = new ContentValues();
value.put("signal_value", cursor.getInt(cursor.getColumnIndex("signal_value")));
values.add(value);
} while (cursor.moveToNext());
}
// ...
return values.toArray(new ContentValues[0]);
Upvotes: 0
Reputation: 94429
Your using a do...while loop, the do while loop will execute an extra iteration because the condition is checked after each iteration, not before. The code gets past your guard condition and enters the loop, which then executes 2x when there is one result.
Switch the loop to a while loop and this should work fine.
int count = 0;
if (cursor.getCount() > 0) {
cursor.moveToFirst();
while (cursor.moveToNext()) {
values[count] = new ContentValues();
values[count].put("signal_value", cursor.getInt(cursor.getColumnIndex("signal_value")));
values[count].put("latitude", cursor.getInt(cursor.getColumnIndex("latitude")));
values[count].put("longitude", cursor.getInt(cursor.getColumnIndex("longitude")));
values[count].put("timestamp", cursor.getLong(cursor.getColumnIndex("timestamp")));
values[count].put("network", cursor.getString(cursor.getColumnIndex("network")));
count++;
}
}
cursor.close();
Upvotes: 0