【问题标题】:Cursor Exception during Async Task异步任务期间的光标异常
【发布时间】:2016-03-22 20:22:49
【问题描述】:

我正在运行一个后台任务,它会下载一个 JSON 文件,对其进行解析,然后将其添加到 SQLite 数据库的内容中。

我在运行时遇到了一些错误。

引起:android.database.CursorWindowAllocationException:光标 2048 kb 的窗口分配失败。 # 打开 Cursors=728 (# cursors 由这个 proc=728 打开)

E/CursorWindow: 无法分配 CursorWindow '/data/data/com.mycompany.inventory/databases/dbInventory.sql' 的大小 2097152 由于错误 -12。

JSON 中有大约 1500 个项目。

这是我的异步任务调用的方法:

public void addModelsToDB(JSONObject dict){
        String  insertQuery  = "";
        String  deleteQuery  = "DROP TABLE IF EXISTS 'tblModels'";
        String  createQuery  = "CREATE TABLE 'tblModels' ('modelsID' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,'makeKey' INTEGER, 'modelName' TEXT, 'modelKey' INTEGER)";

        Cursor cursor = dbLocals.executeRawQuery(deleteQuery, null);
        cursor.moveToFirst();
        cursor = dbLocals.executeRawQuery(createQuery, null);
        cursor.moveToFirst();

        try {
            JSONArray dicRecordSet  = dict.getJSONArray("Recordset");
            JSONObject dicRecords = dicRecordSet.getJSONObject(0);
            JSONArray arrRecords = dicRecords.getJSONArray("Record");


            for (int i = 0; i < arrRecords.length(); i++) {
                JSONObject record = arrRecords.getJSONObject(i);
                insertQuery = "INSERT INTO 'tblModels' VALUES(" + null +  ", "
                        + record.getString("MODMAKlMakeKey") + ", '"
                        + record.getString("MODvc50Name").replaceAll("'", "''") + "', "
                        + record.getString("MODlModelKey")
                        +")";
                cursor =  dbLocals.executeRawQuery(insertQuery, null);
                cursor.moveToFirst();
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }

        cursor.close();
    }

我的数据库管理员返回一个游标。

public Cursor executeRawQuery(String query, String[] selectionArgs) {
        Cursor cursor = databaseConn.rawQuery(query, selectionArgs);
        return cursor;
    }

我做错了什么?

【问题讨论】:

    标签: android json sqlite cursor


    【解决方案1】:

    您不能重用游标变量,因为它会遮蔽原始变量,因此您无法关闭它:

    Cursor cursor = dbLocals.executeRawQuery(deleteQuery, null);
    

    然后

    cursor =  dbLocals.executeRawQuery(insertQuery, null);
    

    第二个赋值意味着你不能关闭原来的光标。

    另外,你为什么要在这里创建表格?

    编辑:

    像这样使用它:

    public void addModelsToDB(JSONObject dict){
        String  insertQuery  = "";
        String  deleteQuery  = "DROP TABLE IF EXISTS 'tblModels'";
        String  createQuery  = "CREATE TABLE 'tblModels' ('modelsID' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,'makeKey' INTEGER, 'modelName' TEXT, 'modelKey' INTEGER)";
    
        Cursor cursor = dbLocals.executeRawQuery(deleteQuery, null);
        try {
            cursor.moveToFirst();
            cursor = dbLocals.executeRawQuery(createQuery, null);
            cursor.moveToFirst();
        } finally {
            cursor.close();
        }
    
        try {
            JSONArray dicRecordSet  = dict.getJSONArray("Recordset");
            JSONObject dicRecords = dicRecordSet.getJSONObject(0);
            JSONArray arrRecords = dicRecords.getJSONArray("Record");
    
    
            for (int i = 0; i < arrRecords.length(); i++) {
                JSONObject record = arrRecords.getJSONObject(i);
                insertQuery = "INSERT INTO 'tblModels' VALUES(" + null +  ", "
                        + record.getString("MODMAKlMakeKey") + ", '"
                        + record.getString("MODvc50Name").replaceAll("'", "''") + "', "
                        + record.getString("MODlModelKey")
                        +")";
                cursor =  dbLocals.executeRawQuery(insertQuery, null);
                try {
                    cursor.moveToFirst();
                } finally {
                    cursor.close();
                }
            }
    
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    

    【讨论】:

    • 啊。谢谢你的指点。每隔一段时间我需要清除本地数据库并重新开始,我发现删除表更容易。我应该换一种方式吗?
    • 我会删除,但删除表也可以。只是好奇你为什么在这里这样做。
    • 你是说在删除查询后关闭光标。为 insertQuery 实例化一个新的 Cursor 然后关闭它?
    • 是的,在删除表后关闭该游标。之后,您可以重用变量“光标”。
    • 感谢您的帮助!
    【解决方案2】:

    您应该在使用游标后关闭它们。在循环内部,每次迭代都创建一个游标,而无需关闭它。显然,打开游标的数量是有限制的,而您达到了该限制。

    【讨论】:

    • 我不这样做吗?我正在调用 cursor.close();
    • 那是您最后使用的,那么您在循环中失去参考的之前的呢?
    猜你喜欢
    • 2012-09-27
    • 2012-10-26
    • 1970-01-01
    • 2021-07-05
    • 1970-01-01
    • 1970-01-01
    • 2015-10-03
    • 2020-12-25
    • 2017-09-26
    相关资源
    最近更新 更多