【问题标题】:Android database cursor lifetimeAndroid 数据库游标生命周期
【发布时间】:2011-09-03 10:51:29
【问题描述】:

在过去的三天里,我一直在尝试理解和解决这个问题。 我有多个 ListActivity,每个都查询同一个数据库。在每个活动中,我分别在 onPause() 和 onResume() 中关闭和重新打开数据库连接。我用游标填充列表适配器,我也关闭并重新打开:

@Override
public void onPause(){
    super.onPause();

    if(currentCursor != null){
        currentCursor.close();
        currentCursor = null;
    }

    if(mDbHelper != null){
        mDbHelper.close();
        mDbHelper = null;
    }
}

@Override
public void onResume(){
    super.onResume();
    if(mDbHelper == null){
        mDbHelper = new DbHelper(this);
        mDbHelper.open();
    }

    if(currentCursor == null){
        new LoadNewListTask().execute();
    }
}


private class LoadNewListTask extends AsyncTask<String, Void, String> {
    ProgressDialog dialog;

    @Override
    protected void onPreExecute() {
        dialog = new ProgressDialog(context);
        dialog.setMessage("Loading...");
        dialog.show();
    }
    @Override
    protected String doInBackground(String... arg0) {
        try{
            currentCursor = mDbHelper.fetchNewRows();
        }catch(Exception e){}
        return null;
    }
    @Override
    protected void onPostExecute(String arg){
        if(dialog != null && dialog.isShowing()){
            dialog.dismiss();
        }
        if(currentCursor != null && currentCursor.getCount()>0){
            String[] from = new String[]{DbHelper.KEY_ID, sortingColumn};
            int[] to = new int[]{R.id.ai_about_author_btn, R.id.ai_author_name};

            MyAlphabetizedAdapter notes = new MyAlphabetizedAdapter(this, R.layout.author_index_item, currentCursor, from, to, sortingColumn);
            setListAdapter(notes);
        }
    }
}

乍一看它很好用,但是当我在活动之间快速移动时,有时会遇到烦人的光标异常,有人说:

05-01 14:45:05.849: ERROR/AndroidRuntime(1145):
java.lang.IllegalStateException: attempt to acquire a reference on a
close SQLiteClosable
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:31)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:56)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:49)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:49)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1118)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1092)
05-01 14:45:05.849: ERROR/AndroidRuntime(1145):     at
apt.tutorial.Restaurant.getAll(Restaurant.java:14)

另一个人这样说(这在 2.1 设备上经常发生):

09-03 11:30:19.713: INFO/dalvikvm(2541): Uncaught exception thrown by finalizer (will be discarded):
09-03 11:30:19.713: INFO/dalvikvm(2541): Ljava/lang/IllegalStateException;: Finalizing cursor android.database.sqlite.SQLiteCursor@45b99828 on null that has not been deactivated or closed
09-03 11:30:19.713: INFO/dalvikvm(2541):     at android.database.sqlite.SQLiteCursor.finalize(SQLiteCursor.java:596)
09-03 11:30:19.713: INFO/dalvikvm(2541):     at dalvik.system.NativeStart.run(Native Method)

还有一个我的 ListActivities 实现了 AlphabetIndexer,我必须在其中传递光标。在我离开活动并使用返回按钮返回后,发生了非常奇怪的事情。该列表已填充(如预期的那样),但是当我尝试使用快速滚动时,即使我重新创建了它并重新填充了 onResume() 列表,我也会在光标上得到一个空异常。

对我来说,操作系统似乎无法正确处理多个光标,或者我在这里错过了什么?

感谢您的帮助。

【问题讨论】:

    标签: android exception sqlite cursor listactivity


    【解决方案1】:

    一般来说,我遇到了试图保持多个游标活动的活动的问题。尤其是在尝试使用托管游标时,我现在尽可能避免使用托管游标(加上它们已被弃用)。现在,我尝试做的是打开游标,用我需要的数据填充对象数组,关闭游标,然后使用 ArrayAdapter 填充 ListView。如果您确实需要保持光标处于活动状态,并且仅在堆栈上的其他活动正在更改数据时才需要,请使用光标管理器,或者更好的是使用更新的 CursorLoader。执行此操作时,请勿关闭光标,因为您的活动将为您管理光标的生命周期。

    【讨论】:

    • 我在我的其他项目中使用 ArrayAdpters 和自定义对象,一切正常。使用游标需要更少的资源,但我不知道管理它们会非常令人沮丧。
    • 是的 - 我去过那里(很明显,但我仍然没有回答的问题之一)。我有一项活动,我试图同时管理 3 或 4 个游标。最终奏效的是使用 ArrayAdapter 方法,除了 1 个游标外,我需要保持活动状态(数据会改变)。
    • 从内存的角度来看,我不认为使用数组代替游标是个好主意
    【解决方案2】:

    由于您启动了一个异步任务并快速离开活动,这意味着当任务返回时您将离开此活动,因此已调用 onPause() 并且光标未关闭。您可以尝试取消onPause() 中的异步任务。

    【讨论】:

    • 你说得很好,但是我等待 AsyncTask f 完成,然后我转到下一个活动。
    • 嗯,你检查过 fetchNewRows() 是否返回 null 吗?
    • 是的,我做到了,它返回数据。当我不关闭光标 onPause() 时,一切都按预期工作,但我们不应该吗? SimpleCursorAdapter 是否负责光标的生命周期?
    • 不,适配器只是根据活动生命周期使用您提供给他的光标。游标生命周期的处理应该由活动管理。
    • 但我怎样才能让活动开始管理光标?以前我使用 startManagingCursor() 但是这个方法已经被贬值了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    相关资源
    最近更新 更多