4

我在 s 中有一系列ListView对象,这些对象由 a从活动中获取 aFragment填充。据我了解,所有数据库和关闭操作都完全由和处理,因此我在任何代码中都没有调用任何内容。CursorAdapterCursorLoaderManagerCursorLoaderManagerContentProvider.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告诉我何时或正在被调用,似乎在给定适配器的第一次发生这种情况,而对于另一个适配器则发生了很多s。当用户在应用程序中导航了很多之后,也会发生这种情况。getView(...)getItem(...)getItemId(...)getView(...)getView(...)

这让我想知道Cursor适配器的 是否保留在 中CursorAdapter,但被ContentProvider或错误关闭Loader。这可能吗?我应该CursorAdapter根据应用程序/活动/片段生命周期事件进行任何内务管理吗?

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);
}

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

IllegalStateException:尝试重新打开已经关闭的对象。SimpleCursorAdapter 问题

刚刚曝光的重要新信息

我在项目的其他地方发现了一些其他代码,它们没有使用Loaders 并且没有正确管理它Cursor的 s。我刚刚切换了这段代码以使用与上面相同的模式;但是,如果这可以解决问题,则表明Cursor项目的某个部分中未受管理的人可能会在其他地方杀死受适当管理的人。

停在附近。

新信息的结果

那并没有解决它。

新理念

@Override
onDestroyView() {
    getActivity().getLoaderManager().destroyLoader(mFragmentId);
    //any other destroy-time code
    super.onDestroyView()
}

即可能是的,我应该CursorAdapter(或者更确切地说CursorLoader符合生命周期事件)进行内务处理。

新理念的成果

没有。

以前的想法

一旦我添加了一个小调整,结果就可以工作了!但是它太复杂了,我可能应该重写整个问题。

4

2 回答 2

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
    }
});
于 2013-02-19T11:45:48.567 回答
0

您可以尝试将 null 路径而不是光标放入适配器构造函数中。然后在适配器中使用 SwapCursor(Cursor 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);
    }
于 2015-07-29T12:17:37.630 回答