从具有0行、64列的CursorWindow中无法读取第0行、第0列的行。

3

我有时在我的日志中看到这个错误:

从具有 0 行、64 列的 CursorWindow 中读取第 0 行、第 0 列失败。

首先,需要讲述一下背景。我的应用程序运行在我们组织中的许多设备上。目前,它主要在大约 20 台 Samsung Note 8 设备、2 台 Samsung Note 10.1 设备以及其他几个设备上运行。到目前为止,这个问题只发生在 2 台 Note 8 设备上。对于所有其他设备,它似乎都能正常工作。

应用程序的工作原理是:用户使用应用程序收集信息,如文本、照片、签名等等,并将所有这些内容存储/插入到 SQLite 数据库中,作为提交表中的一行。提交表共有 64 列,以适应每个字段的收集。总是在后台运行一个同步方法(它是一个 AsyncTask,在 runnable thread 内执行,因此即使关闭应用程序,仍会同步数据,除非您从 Android 任务管理器中滑动关闭它),该方法将数据同步到远程服务器,并每隔 10 秒检查一次是否需要进行同步,例如如果插入了新的提交,那么它将开始同步该提交。当提交成功与服务器同步并收到成功响应后,它将从设备的数据库中删除。到目前为止,它一直表现良好,并成功同步了数千个提交等等。然而,偶尔会有一两台特定的 Note 8 平板电脑出现该问题。我已经尝试过很多次来重新创建这个错误,但每次测试都能正常工作,我已经尝试过各种情况来测试它。

我的代码有数千行,所以我将尽可能保持其相关性。首先,这是可运行代码的相关代码:

public Runnable myRunnable = new Runnable()
 {

    @Override
    public void run()
    { 
       count ++;
                if(count >= 10)
                {
                    android.util.Log.w("     SYNC     ", "---------------");
                    android.util.Log.w("     SYNC     ", "Checking if sync method is busy");
                    if(!syncBusy)
                    {
                        android.util.Log.w("     SYNC     ", "Sync method OPEN");
                        doSync();//This will start doing sync.
                        count = 0;
                    }
                    else
                    {
                    android.util.Log.w("     SYNC     ", "Sync method BUSY, will try again in 10 seconds");
                    android.util.Log.w("     SYNC     ", "---------------");
                    }
                }
                if(count == 1 && !syncBusy)
                {
                    checkSubmissionsLefttoSync();
                }
       mHandler.postDelayed(myRunnable, 1000);
    }
};

然后,doSync()方法是我上传的地方,也是我遇到错误的地方。它有1000多行,所以我不想在这里发布代码。我可以说的是,除了产生上述错误的一两个例外设备外,它对所有设备都能百分百工作。
此外,在sync方法中实际遍历数据库的部分会被发布:
        databaseHelper = new Handler_Database(this);
        Cursor cursor2 = databaseHelper.getAllUnsyncedSubmissions();

        if(cursor2.getCount() > 0) 
        {
            if(cursor2.moveToFirst())
            {

              do
                {
                    try
                    {
                       //doing lookups here and populating sync arrays
                    }
                    catch (IllegalStateException e)
                    {
                        //Do Nothing
                    }
                    catch (NullPointerException e)
                    {
                        //Do Nothing
                    }
                }
                while(cursor2.moveToNext());

            }
            else
            {

            }
        }
        else
        {

        }
         cursor2.close();
         databaseHelper.close();

我注意到了另一个问题,但我不确定它是否是一个问题,当我运行应用程序时,logcat会输出以下行约6或7次:

12:48:11.115 7416 #7416 DEBUG SQLiteOpenHelper DB version : 60

我的应用程序启动时会显示自己的警告消息,这些消息仅显示一次。然而,数据库版本和其他信息被多次写入logcat。这是个问题吗?这是否意味着我的数据库存在某种错误,创建了多个实例?
所有应用程序都使用来自playstore的已签名apk进行更新。我的onUpgrade方法如下:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
    // Drop older table if existed
    db.execSQL("DROP TABLE IF EXISTS " + TABLE_SUBMISSIONS);

    // Create tables again
    onCreate(db);
}

这对于其他平板电脑和设备都很好用。它们都可以自动从Play商店更新并继续正常工作。然而,为什么logcat会输出那些行多次呢?这可能是我在本贴开头提到的错误的一部分吗?任何可能的见解都将不胜感激。我已经为此苦苦挣扎了几周,但无法在我的代码中找到任何错误。

更新 1:

我刚看到这个警告:

08:30:58.710 16745 #16745 WARN CursorWindow Window is full: requested allocation 307333 bytes, free space 249426 bytes, window size 2097152 bytes

我想这可能是我的问题的根源。有什么有效的解决方法吗?

更新 2:

我认为一个解决办法可能是限制我从游标中检索的列。例如,所有小文本值/列。然后,在确定占用太多空间的每个列之后,创建一个新的查询。你认为这是一个解决方案吗?有人吗?

更新 3:

这可能起作用,我想我会在最初的游标回收后使用单独的游标来处理大字段。就像这样(我只是写了一些伪代码):
Cursor c = db.rawQuery("SELECT Column1, Column2 .... FROM table " + ... , ...);

解决方案:

你可以在这里查看我的解决方案:https://stackoverflow.com/a/26797130/1518916


1
这是一个在可运行线程内执行的AsyncTask,所以即使应用被关闭,它仍会在后台同步数据,除非你从Android任务管理器中滑动关闭它。我认为如果您的应用程序关闭,您的线程/异步将不再运行。考虑使用SERVICE替代。当活动被销毁时,Thread和Async也会关闭。 - Blaze Tama
@BlazeTama 我同意你的看法。 - Zala Janaksinh
你在哪里遇到了这个错误(无法读取第0行,第0列...)? - pskink
在我遍历数据库的同步方法内,@pskink。读取//doing lookups here and populating sync arrays的那个部分。 - Janpan
所以你正在尝试从一个空的CursorWindow中读取第一行,请参见:http://androidxref.com/4.4_r1/xref/frameworks/base/libs/androidfw/CursorWindow.cpp#257 - pskink
显示剩余3条评论
2个回答

7
我已经完成了解决方案,现在它可以正常工作。基本上,重要的是不要将大量数据存储在Android的SQLite数据库中。当处理图像时,应只存储URI并保留设备上的图像。但是,如果必须这样做,那么建议不要将所有图像数据加载到同一个游标中,而是将它们分开并执行多个查询。
请参见我的答案:https://stackoverflow.com/a/26797130/1518916

3

当您的图片过大时,会出现此错误。在存储之前,请将图片的url存储或压缩图片。


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