2012-04-04 3 views
1

Я немного потерял это. Как я могу получить OutOfBounds? Есть ли ограничение по размеру (кроме sizeof (int))?ArrayIndexOutOfBoundsException error ... почему?

Возможно, потому что несколько нитей может сюда приехать? Линия пользовательского интерфейса и нить службы?

java.lang.ArrayIndexOutOfBoundsException на kenyu73.realsignal.DatabaseWrapper.getSignalValues ​​(DatabaseWrapper.java:137) на kenyu73.realsignal.DatabaseWrapper.getSignalValues ​​(DatabaseWrapper.java:116) в kenyu73.realsignal.BarScaleGraph $ buildGraphThread.drawGraph (BarScaleGraph.java:128) на kenyu73.realsignal.BarScaleGraph $ buildGraphThread.execute (BarScaleGraph.java:94) в kenyu73.realsignal.BarScaleGraph $ buildGraphThread.run (BarScaleGraph.java:74)

Кроме того, я вызываю эти методы классов с помощью статического экземпляра . Я думаю, что потоки конкурируют за одни и те же переменные ??? Мысли?

класс BarScaleGraph

ContentValues[] values = DatabaseWrapper.getInstance().getSignalValues(getContentResolver(), signal_type, false); 

класс DatabaseWrapper

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: Собираюсь попробовать это - добавить синхронизированный к экземпляру

// grab static instance so we only have one db wrapper 
public static synchronized DatabaseWrapper getInstance() { 
    return instance; 
} 
+0

Вы никогда не объявляли массив в своем фрагменте. Проводка этого поможет нам решить вашу проблему. –

+0

В чем же вы получаете исключение? –

+0

Этого не бывает много. У меня было только два отчета об этом. Этот метод вызывается несколькими потоками. Мне интересно, если это причина? Существует пользовательский интерфейс и поток услуг. – kenyu73

ответ

1

Я бы предположил, что это состояние гонки, где отсчет изменение между потоками ... попытаться синхронизировать метод:

public synchronized ContentValues[] getSignalValues(...){ 
    ... 
} 

Если предыдущий вам не подходит, всегда так:

public ContentValues[] method1(...){ 
    synchronized (monitor1) { 
     ... 
    } 
} 

public ContentValues[] method2(...){ 
    synchronized (monitor2) { 
     ... 
    } 
} 

Это позволило бы решить проблему, но я хотел бы попытаться предотвратить такого рода методологии, используя другую архитектуру.

+0

... очень возможно. Интересно, могу ли я использовать синхронизацию на моем getInstance(). Таким образом, любой метод безопасен? Просто гадать ... Я не эксперт по теме. Я могу их сделать, но не могу объяснить их (= – kenyu73

+1

Если это проблема с условиями гонки, ваше предложение не будет ее преодолевать. Оба потока приобрели бы экземпляр в синхронном порядке, и оба будут асинхронно вызывать метод getSignalValues. – TacB0sS

+0

Хорошая точка. Проблема в том, что у меня есть много общедоступных методов, которые доступны с несколькими потоками. Наверное, мне пришлось бы добавлять синхронизацию по всем методам в этом вызове. Это все считается условием гонки. У меня хорошие аргументы что наличие нескольких потоков в одном методе невозможно, так как каждый из них получит свой собственный экземпляр. Я не сомневаюсь, что если использовать статический экземпляр mutes, тем не менее, я бы подумал, что статический экземпляр сделает все методы статичными по своей сути. – kenyu73

0

Что об этом,

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(); 
+0

Разве это не бесконечный цикл? –

+0

@ kmb385 - Я не упоминаю пока часть. – user370305

+0

Это был бы взлом, который, вероятно, поймал бы ошибку, но теоретически getCount() должен быть мертв. – kenyu73

0

Вы используете сделать ... в то время цикла, то делать во время цикла будет выполнять дополнительную итерацию, поскольку условие проверяется после каждой итерации, не раньше. Код проходит через ваше защитное условие и вводит цикл, который затем выполняет 2x, когда есть один результат.

Переключите цикл в цикл while, и это должно работать нормально.

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(); 
+0

Нет, его петля в порядке. Это немного запутанно, но все в порядке. Он предварительно проверяет, что счетчик больше нуля, перемещается в первую строку, обрабатывает его в теле цикла и затем переходит к следующей строке. 'moveToNext' возвращает' false', если курсор заканчивается не в строке, а цикл завершается. –

+0

Эта ошибка возникает только раз в то время. Это непротиворечиво. – kenyu73

+0

Отправьте код метода getCount –

2

Единственный разумный ответ, что cursor.getCount() возвращается число меньше, чем число петель, что ваш do..while цикл делает. Я не вижу ошибки в логике вашего цикла do..while (хотя это необычная логика, см. Ниже).

Я предполагаю, что это живой курсор, а что-то еще удаление добавление соответствующих строк во время работы вашего цикла. Единственный реальный способ узнать - добавить инструменты в код, чтобы вы могли увидеть, что вернулось cursor.getCount(), что count было в начале каждой итерации цикла и т. Д.

Если вы на самом деле не волнует, почему и просто хочу, чтобы остановить происходящее, вы могли бы использовать вместо List:

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()]); 
} 

(. Или код для этого эффекта)

Там я использовал временный связанный список, поэтому мне все равно, что возвращает cursor.getCount, преобразовывая его в массив, когда мы закончили. Я также использовал более распространенную идиому для циклических курсоров (поскольку курсоры начинаются непосредственно перед первой строкой, while (cursor.moveToNext()) - это удобный способ для цикла), а не (снова), что я видел логическую ошибку в вашем do..while, но мне нравится простота и точность while (cursor.moveToNext()).

+0

Спасибо за предложение. Этот метод вызывается из пользовательского интерфейса и из потока услуг. Считаете ли вы, что два потока, обращаясь к одному и тому же методу, могут вызвать это? Я обновляю свой первоначальный вопрос с дополнительной информацией. – kenyu73

+1

@ kenyu73: Я не вижу, как. Курсор не разделяется между потоками, все является локальным для функции. Два потока, называя их одновременно, должны быть в порядке. –

+0

Метод вызывается с использованием статического экземпляра. Будет ли это иметь значение? xyz = "DatabaseWrapper.getInstance(). getSignalValues ​​(..);" – kenyu73

0

Хотя я не уверен, что проблема в том, что вы можете сделать это более безопасным способом:

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]); 
+0

Спасибо за идею. Если я не могу понять причину, ArrayList - хороший хак, чтобы обойти это. – kenyu73

0

cursor.moveToFirst может быть возвращение ложным. Попробуйте обертывание, что в заявлении, если:

if (cursor.moveToFirst()) { 
    do.... 
} 
+0

Это просто вызывает вопрос о том, почему 'getCount' возвращает'> 0', но 'moveToFirst' возвращает' false'. –

Смежные вопросы