尝试重新打开已关闭的对象:java.lang.IllegalStateException:?

15

我知道这个问题在SO上已经被问了很多次,但是我无法找出自己的确切问题。

我正在使用以下代码从数据库(Table1)获取数据并根据检索值更新另一个Table2。 在某些android版本中它可以正常工作,但当我尝试使用Android 4.0.3进行测试时,我会得到以下错误: java.lang.IllegalStateException:?.attempt to re-open an already-closed object at sum_cursor.moveToNext();.

我在AsyncTask中使用这段代码。

 /** Sum of total matched values*/
            Cursor sum_cursor = db.gettotalMatchvalue(this);
             if(sum_cursor!=null)
             {
                 sum_cursor.moveToFirst();
                 for(int j=0; j<sum_cursor.getCount();j++)
                 {    
                     float totalmatchedscore = sum_cursor.getInt(0);
                     float totalingredients = Float.parseFloat(sum_cursor.getString(sum_cursor.getColumnIndex(APPDatabase.CK_TOTALINCREDIENTS)));
                     /**average = totalscore/totalingredients*/
                     double average = totalmatchedscore/totalingredients;
                     int id = Integer.parseInt(sum_cursor.getString(sum_cursor.getColumnIndex(APPDatabase.CK_ID))); 

                 db.updateAverage(id, average); 
                 sum_cursor.moveToNext(); //Here is the problem
                 }  
             }   
             db.close();  

我的更新方法的代码

/** Update average */
public void updateAverage(int id,double average)
{
    SQLiteDatabase db = getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(CK_FINALVALUE,average);
    db.update(TABLE, values,CK_ID+" = "+id , null);   
}

我在这里做错了什么?

我知道很多人都会遇到这种情况。你们能帮帮我吗?

谢谢你们的帮助。


也许你在异步任务之外关闭了数据库。你有检查过吗? - Todd Davies
4.0.3系统运行速度是否比您使用的其他系统更快?如果是,可能会出现一些竞争条件。 - Todd Davies
1
一个观察:您用于循环遍历光标的代码比必要的复杂。请参阅https://dev59.com/uWgv5IYBdhLWcg3wQ-ud - Graham Borland
3个回答

23

在遍历查询结果时,无法更新表格。这是有好的原因的;如果您要添加的数据会导致正在遍历的数据发生更改,那么您的游标将无法返回有效数据。

updateAverage() 中尝试将数据存回表格会导致问题。您应该在循环期间记住平均值,然后在完成对游标的循环后一次性更新它。

进一步解释您遇到的确切错误:插入新数据的行为会导致数据库关闭当前打开的所有游标,作为一种安全措施。因此,在更新平均值后调用 sum_cursor.moveToNext() 时,游标会感到有些惊讶,因为它已经被关闭了。


感谢您提供的精彩信息。根据您的信息,我得到的是将平均值存储在数组或列表中,然后在另一个循环中进行更新。我是正确的吗? - vinothp
谢谢,我会尝试并让您知道结果。感谢您的即时支持,为此点赞+1。 - vinothp

2
如果你将 db.updateAverage(id, average) 进行注释,会发生什么?

谢谢你的回答。实际上,db.updateAverage(id, average)非常重要。只有在这个更新完成后,我才能进行下一步操作。 - vinothp
@Vinoth 我的意思是,如果你将其注释掉,那么错误会消失吗? - Alexander Kulyakhtin
抱歉Alex,我现在无法测试,因为那部手机是我的朋友的。我只能明天测试并告诉你。这真的很奇怪。 - vinothp
我的意思是,db.updateAverage 似乎是你的代码中唯一一个除你之外没有人能够知道的地方。 - Alexander Kulyakhtin
@Vinoth 也许 db.update 使您当前的 Cursor 无效了。无论如何,db.update 更改了表格内容,而您仍然保留着旧的 cursor,这是不正确的。 - Alexander Kulyakhtin
@Alex 谢谢,现在我该怎么办?你有什么想法吗?我应该把 sum_cursor.moveToNext 移到 db.update 之前,这样会起作用吗? - vinothp

0

您可以通过纯SQL实现您的目标,从架构的角度来看,这是更快、更好的方法,因为所有的逻辑都将在一个SQL事务中。

REPLACE INTO table_where_to_put  SELECT *, (totalmatchedscore/totalingredients) as average  FROM table_with_input_data

使用REPLACEUPDATE


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接