Java ArrayIndexOutOfBoundsException错误。。。为什么?

Java ArrayIndexOutOfBoundsException错误。。。为什么?,java,android,Java,Android,我对这件事有点迷茫。我怎样才能得到一个出界?是否有大小限制(除了sizeof(int)) 可能是因为多个线程可以到这里来?UI线程和服务线程 java.lang.ArrayIndexOutOfBoundsException位于 kenyu73.realsignal.DatabaseWrapper.getSignalValues(DatabaseWrapper.java:137)位于 kenyu73.realsignal.DatabaseWrapper.getSignalValues(Databa

我对这件事有点迷茫。我怎样才能得到一个出界?是否有大小限制(除了sizeof(int))

可能是因为多个线程可以到这里来?UI线程和服务线程

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);
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;
}
数据库包装类

ContentValues[] values = DatabaseWrapper.getInstance().getSignalValues(getContentResolver(), signal_type, false);
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;
}
这个呢,

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

使用do…while循环时,do while循环将执行额外的迭代,因为条件是在每次迭代后检查的,而不是在每次迭代之前检查的。代码通过保护条件进入循环,然后在有一个结果时执行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();

唯一合理的答案是
cursor.getCount()
返回的数值低于
循环执行时的循环数。我没有发现
do..while
循环的逻辑中有错误(尽管这是不寻常的逻辑;请参见下文)

我猜这是一个活动游标,在循环运行时删除并添加相关行。找到答案的唯一真正方法是向代码中添加插装,这样您就可以看到cursor.getCount()返回了什么,每个循环迭代开始时的
count
是什么,等等

如果您并不真正关心原因,只是希望它停止发生,您可以使用
列表来代替:

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()]);
}
public ContentValues[]getSignalValues(ContentResolver cr、int-signal\u-type\u-id、boolean bGroupByLatLon){
字符串sWhere=“信号类型”id=“+信号类型”id;
光标;
if(bGroupByLatLon){
cursor=cr.query(CONSTS.CONTENT\u URI\u GRP\u LATLNG,null,sWhere,null,null);
}否则{
cursor=cr.query(CONSTS.CONTENT\u URI\u LOGGER,null,sWhere,null,null);
}
列表值=新建LinkedList();
内容值输入;
while(cursor.moveToNext()){
entry=newcontentvalues();
entry.put(“信号值”),cursor.getInt(cursor.getColumnIndex(“信号值”));
entry.put(“纬度”,cursor.getInt(cursor.getColumnIndex(“纬度”));
entry.put(“经度”,cursor.getInt(cursor.getColumnIndex(“经度”));
entry.put(“timestamp”、cursor.getLong(cursor.getColumnIndex(“timestamp”));
entry.put(“网络”,cursor.getString(cursor.getColumnIndex(“网络”));
值。添加(条目);
}
cursor.close();
返回values.toArray(新的ContentValues[values.size()]);
}
(或为此编写的代码。)


在这里,我使用了一个临时链表,所以我不在乎cursor.getCount返回什么,当我们完成时,将它转换成一个数组。我还使用了更常见的循环游标的习惯用法(因为游标开始于第一行之前,
while(cursor.moveToNext())
是一种方便的循环方式),我没有(再次)看到您的
do..while
中存在逻辑错误,但我喜欢
while(cursor.moveToNext())的简单和直接

虽然我不确定问题出在哪里,但您可以用更安全的方式:

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]);
List values=new ArrayList();
if(cursor.getCount()>0){
cursor.moveToFirst();
做{
ContentValues值=新的ContentValues();
value.put(“信号值”,cursor.getInt(cursor.getColumnIndex(“信号值”));
增加(价值);
}while(cursor.moveToNext());
}
// ...
返回值.toArray(新的ContentValues[0]);

cursor.moveToFirst可能返回false。尝试将其包装到if语句中:

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

我猜这是一个竞争条件,其中计数是线程之间的变化。。。尝试同步该方法:

public synchronized ContentValues[] getSignalValues(...){
    ...
}
如果前一个不适合您,则始终存在以下问题:

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

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

这可以解决问题,但我会尝试使用不同的体系结构来阻止这种方法。

您从未在代码段中声明过数组。发布这篇文章将帮助我们解决您的问题。您在哪种情况下会得到例外?这种情况很少发生。我只收到两份报告。此方法由多个线程调用。我想知道这是不是原因?有一个UI和一个服务线程。更新了帖子,将可能的线程作为问题包括在内……您是否尝试同步该方法?没有,他的循环很好。这有点复杂,但没关系。他预先检查计数是否大于零,移动到第一行,在循环体中处理它,然后移动到下一行
moveToNext
返回
false
如果光标不在一行上,循环结束。@kmb385:非常确定他使用的是@kmb385-我没有提到while part。这可能是一个可能会捕捉错误的黑客,但理论上,getCount()应该是死机。@kenyu73-是的,你必须为cursor.getCount()声明int并在代码中使用该变量。@user370305:His
do..while
虽然不是通常的方式,但也可以。只有当光标下有一行时,他的逻辑才能成功循环。@user370305:对。毫无疑问。问题是为什么。他的循环体应该只在光标下有一行时执行,逻辑是不寻常的,但没有明显的缺陷。前面有一个
getCount()>0
check,一个
moveToFirst
将他带到身体处理的第一条记录,然后是一个
moveToNe