Android CursorLoader,尝试重新查询已经关闭的游标

发布于 2024-11-08 01:04:43 字数 1490 浏览 1 评论 0原文

我刚刚开始使用新的cursorLoader,但遇到了问题。以下代码只是为了了解游标加载器的工作原理,但当

我恢复此活动时,我不断收到:“尝试重新查询已关闭的游标”。在我开始使用 CursorLoader 之前,该应用程序运行良好。有什么想法吗?

private Cursor getSectionData(CharSequence parent_id) {
    
    String[] projection = new String[] {Titles.SECTION, Titles.TITLE, Titles._ID, Titles.CODE_RANGE,};
    Uri titles =  Titles.CONTENT_URI;
    String select = "" + Titles.PARENT_ID + " match " + parent_id + "";
    CursorLoader loader = new CursorLoader(this, titles, projection, select, null, null);
    Cursor cTitles = loader.loadInBackground();
    
    
    String[] projection1 = new String[] {Codes.CODE, Codes.EXCERPT, Codes._ID,};
    Uri codes =  Codes.CONTENT_URI;
    String select1 = "" + Codes.PARENT_ID + " match " + parent_id + "";
    CursorLoader loader1 = new CursorLoader(this, codes, projection1, select1, null, null);
    Cursor cCodes = loader1.loadInBackground();

    
    
    //Cursor cTitles = db.rawQuery("select section, title, _id, code_range from titles where parent_id match " + parent_id + "", null);
    //startManagingCursor(cTitles);
    //Cursor cCodes = db.rawQuery("select code, excerpt, _id from codes where parent_id match " + parent_id + "", null);
    
    mQuery = "select code, excerpt, _id from codes where parent_id match " + parent_id + "";
    
    //startManagingCursor(cCodes);
    Cursor[] c = {cTitles, cCodes};
    Cursor cursor = new MergeCursor(c);
    startManagingCursor(cursor);
    
    return cursor;

}

I am just starting to play with the new cursorLoader and I am running into problems. The following code is just to understand how the cursorLoader works but I keep getting:

"Trying to requery an already closed cursor", when I resume this activity. The app was working fine before I started playing with the cursorLoader. Any ideas?

private Cursor getSectionData(CharSequence parent_id) {
    
    String[] projection = new String[] {Titles.SECTION, Titles.TITLE, Titles._ID, Titles.CODE_RANGE,};
    Uri titles =  Titles.CONTENT_URI;
    String select = "" + Titles.PARENT_ID + " match " + parent_id + "";
    CursorLoader loader = new CursorLoader(this, titles, projection, select, null, null);
    Cursor cTitles = loader.loadInBackground();
    
    
    String[] projection1 = new String[] {Codes.CODE, Codes.EXCERPT, Codes._ID,};
    Uri codes =  Codes.CONTENT_URI;
    String select1 = "" + Codes.PARENT_ID + " match " + parent_id + "";
    CursorLoader loader1 = new CursorLoader(this, codes, projection1, select1, null, null);
    Cursor cCodes = loader1.loadInBackground();

    
    
    //Cursor cTitles = db.rawQuery("select section, title, _id, code_range from titles where parent_id match " + parent_id + "", null);
    //startManagingCursor(cTitles);
    //Cursor cCodes = db.rawQuery("select code, excerpt, _id from codes where parent_id match " + parent_id + "", null);
    
    mQuery = "select code, excerpt, _id from codes where parent_id match " + parent_id + "";
    
    //startManagingCursor(cCodes);
    Cursor[] c = {cTitles, cCodes};
    Cursor cursor = new MergeCursor(c);
    startManagingCursor(cursor);
    
    return cursor;

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

烟雨扶苏 2024-11-15 01:04:43

我不相信从 loader.loadInBackground() 捕获光标是您想要的。
loadInBackground() 的实现基本上会执行一个查询并返回 UI 线程上的光标,这是您试图避免的。

任何时候在 UI 线程上等待返回值时都要小心。这应该是一个很好的指标,表明这不是您想要的。

我为解决此问题所做的就是重新启动加载程序。
就我而言,我尝试使用操作栏来搜索我的内容。
我的类扩展了 ListFragment 并实现了 LoaderManager.LoaderCallbacks
容纳此功能的 Activity 实现了 OnQueryTextListener 并调用此处的片段,这是我在片段中执行的代码。

public void doSearch(String query) {
    Bundle bundle = new Bundle();
    bundle.putString("query", query);

    getLoaderManager().restartLoader(LoaderMangerIdHelper.INVENTORY, bundle, this);
}

请注意,您必须重新启动加载程序。加载器全部由系统管理。这将导致您的 onCreateLoader 被重新调用。因此,您必须检查其中的查询字符串来设置您的选择。

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
    String SELECTION = "someColumn=?";
    List<String> selectionArgs = new ArrayList<String>();
    selectionArgs.add("someArgs");

    if (bundle != null && bundle.containsKey("query")) {
        SELECTION += " AND columnTitle LIKE ?";
        selectionArgs.add(bundle.getString("query") + "%");
    }

    final String[] SELECTION_ARGS = new String[selectionArgs.size()];
    selectionArgs.toArray(SELECTION_ARGS);

    mLoader = new CursorLoader(getActivity(), RoamPay.Product.CONTENT_URI, null, SELECTION,
            SELECTION_ARGS, null);

    return mLoader;
}

这将在后台启动光标加载。并且回调应该和平常一样。

   @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // Swap the new cursor in. (The framework will take care of closing the
        // old cursor once we return.)
        mAdapter.swapCursor(data);

        // The list should now be shown.
        if (isResumed()) {
            setListShown(true);
        } else {
            setListShownNoAnimation(true);
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // This is called when the last Cursor provided to onLoadFinished()
        // above is about to be closed. We need to make sure we are no
        // longer using it.
        mAdapter.swapCursor(null);
    }

I don't believe that capturing the Cursor from loader.loadInBackground() is what you want.
The implementation for loadInBackground() basically does a query and returns you the cursor on the UI thread, which is what your trying to avoid.

Be cautious anytime you are waiting on the UI thread for a return value. It should be a good indicator that this is not something you want.

What I did to fix this issue was to restart the loader.
In my case, I'm trying to use the action bar to search my content.
My class extends ListFragment and implements LoaderManager.LoaderCallbacks
The Activity that houses this implements OnQueryTextListener and is calling into the fragment here is the code that I'm doing in the fragment.

public void doSearch(String query) {
    Bundle bundle = new Bundle();
    bundle.putString("query", query);

    getLoaderManager().restartLoader(LoaderMangerIdHelper.INVENTORY, bundle, this);
}

Note that you must restart the loader. The loaders are all managed by the system. This will cause your onCreateLoader to get re-called. So you'll have to check for query string in there to set your selection.

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
    String SELECTION = "someColumn=?";
    List<String> selectionArgs = new ArrayList<String>();
    selectionArgs.add("someArgs");

    if (bundle != null && bundle.containsKey("query")) {
        SELECTION += " AND columnTitle LIKE ?";
        selectionArgs.add(bundle.getString("query") + "%");
    }

    final String[] SELECTION_ARGS = new String[selectionArgs.size()];
    selectionArgs.toArray(SELECTION_ARGS);

    mLoader = new CursorLoader(getActivity(), RoamPay.Product.CONTENT_URI, null, SELECTION,
            SELECTION_ARGS, null);

    return mLoader;
}

This starts the cursorLoading in the background. And the callbacks should be the same as usual.

   @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // Swap the new cursor in. (The framework will take care of closing the
        // old cursor once we return.)
        mAdapter.swapCursor(data);

        // The list should now be shown.
        if (isResumed()) {
            setListShown(true);
        } else {
            setListShownNoAnimation(true);
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // This is called when the last Cursor provided to onLoadFinished()
        // above is about to be closed. We need to make sure we are no
        // longer using it.
        mAdapter.swapCursor(null);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文