IllegalStateException“尝试从ContentProvider中的SimpleCursorAdapter中重新打开已经关闭的对象”

时间:2013-02-19 11:41:03

标签: android android-contentprovider android-cursoradapter android-loadermanager android-loader

我在ListView中有一系列Fragment个对象,其中CursorAdapter填充CursorLoaderManager来自活动Cursor 。据我了解,所有数据库和LoaderManager关闭操作都由ContentProvider.close()完全处理,所以在任何代码中我都不会调用02-19 11:07:12.308 E/AndroidRuntime(18777): java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery (mSql = SELECT * FROM privileges WHERE uuid!=?) 02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:33) 02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:82) 02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:164) 02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:147) 02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:178) 02-19 11:07:12.308 E/AndroidRuntime(18777): at android.database.CursorWrapper.moveToPosition(CursorWrapper.java:162) 02-19 11:07:12.308 E/AndroidRuntime(18777): at android.widget.CursorAdapter.getView(CursorAdapter.java:241) 在任何事情上。

然而,有时我得到这个例外:

CursorAdapter

我在我的getView(...)中添加了一些日志代码,告诉我何时调用getItem(...)getItemId(...)getView(...),似乎第一次发生这种情况对于给定的适配器,getView(...)用于另一个适配器的大量Cursor之后。它也发生在用户经常浏览应用程序之后。

这让我想知道CursorAdapter中是否保留了ContentProvider适配器,但LoaderCursorAdapter错误地关闭了。{1}}。这可能吗?我应该根据应用/活动/片段生命周期事件对ContentProvider进行任何内务管理吗?

class MyContentProvider extends ContentProvider { //... @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteDatabase db = mOpenHelper.getReadableDatabase(); Cursor query = db.query(getTableName(uri), projection, selection, selectionArgs, null, null, sortOrder); query.setNotificationUri(getContext().getContentResolver(), uri); return query; } //... } 查询方法:

LoaderCallbacks

典型的LoaderCallbacks<Cursor> mCallbacks = new LoaderCallbacks<Cursor>() { @Override public void onLoaderReset(Loader<Cursor> loader) { mArticleAdapter.swapCursor(null); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { if(cursor.isClosed()) { Log.d(TAG, "CURSOR RETURNED CLOSED"); Activity activity = getActivity(); if(activity!=null) { activity.getLoaderManager().restartLoader(mFragmentId, null, mCallbacks); } return; } mArticleAdapter.swapCursor(cursor); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { triggerArticleFeed(); CursorLoader cursorLoader = null; if(id == mFragmentId) { cursorLoader = new CursorLoader(getActivity(), MyContentProvider.ARTICLES_URI, null, ArticlesContentHelper.ARTICLES_WHERE, ArticlesContentHelper.ARTICLES_WHEREARGS, null); } return(cursorLoader); } };

CursorAdapter

public ArticlesCursorAdapter(Context context, Cursor c) { super(context, c, 0); mImageloader = new ImageLoader(context); } 构造函数:

ContentProvider

我已经阅读了这个问题但不幸的是它没有得到我的问题的答案,因为它只是建议使用Loader,我是。

IllegalStateException: attempt to re-open an already-closed object. SimpleCursorAdapter problems

重要的新信息只是光明

我在项目的其他地方发现了一些其他代码,这些代码没有使用Cursor而没有正确管理Cursor。我刚刚将此代码切换为使用与上面相同的模式;但是,如果这样可以解决问题,则表明项目某个部分中的非托管@Override onDestroyView() { getActivity().getLoaderManager().destroyLoader(mFragmentId); //any other destroy-time code super.onDestroyView() } 可以在其他地方杀死正确管理的文件。

坚持下去。

新信息的结果

这没有解决它。

新IDEA

CursorAdapter

即可能是的,我CursorLoader上进行内务管理(或者更确切地说,{{1}}与生命周期事件一致。)

新想法的结果

不。

以前的想法

一旦我添加了一个小小的调整,我就开始工作了!然而,它太复杂了,我应该重写整个问题。

2 个答案:

答案 0 :(得分:0)

您是否更新了数据集?可能是由于通知了内容解析器的更改而重新加载了游标:

getContentResolver().notifyChange(URI, null);

如果您设置了通知URI,则会触发当前光标关闭以及光标加载器返回的新光标。如果已注册onLoadCompleteListener,则可以获取新光标:

mCursorLoader.registerListener(0, new OnLoadCompleteListener<Cursor>() {
    @Override
    public void onLoadComplete(Loader<Cursor> loader, Cursor cursor) {
        // Set your listview's CursorAdapter
    }
});

答案 1 :(得分:0)

您可以尝试路径null而不是游标到适配器构造函数。然后在适配器中加载SwapCursor(光标c),移动光标数据的初始化并在数据加载器的OnLoadFinished(Loader loader,Cursor data)方法中调用它。

enter code here
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
    // ... building your query here
       mSimpleCursorAdapter = new mSimpleCursorAdapter(getActivity().getApplicationContext(),
           layout, null, from, to, flags);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
       contentAdapter.swapCursor(data);
    }