Android的CursorLoaderAndroid、CursorLoader

2023-09-04 11:54:50 作者:抬起头、阳光依旧灿烂

我刚开始用新的cursorLoader玩,我遇到了问题。下面code是刚刚了解cursorLoader是如何工作的,但我不断收到:

试图重新查询,并已经关闭光标,当我恢复这一活动。该应用程序工作正常之前,我开始与cursorLoader玩。任何想法?

 私人光标getSectionData(CharSequence的PARENT_ID){

    的String []投影=新的String [] {Titles.SECTION,Titles.TITLE,Titles._ID,标题code_RANGE,};
    乌里标题= Titles.CONTENT_URI;
    串选择=+ Titles.PARENT_ID +匹配+ PARENT_ID +;
    CursorLoader装载机=新CursorLoader(这一点,职称,投影,选择,NULL,NULL);
    光标cTitles = loader.loadInBackground();


    的String [] projection1 =新的String [] {codeS code,codes.EXCERPT,codes._ID,};
    乌里codeS = codes.CONTENT_URI;
    字符串选择一=+ codes.PARENT_ID +匹配+ PARENT_ID +;
    CursorLoader loader1 =新CursorLoader(这一点,codeS,projection1,选择一,NULL,NULL);
    光标C codeS = loader1.loadInBackground();



    //光标cTitles = db.rawQuery(选段,标题,_id,$ C $从标题c_range那里PARENT_ID匹配+ PARENT_ID +,NULL);
    // startManagingCursor(cTitles);
    //光标C codeS = db.rawQuery(选择code,摘录,_id从codeS,其中PARENT_ID匹配+ PARENT_ID +,NULL);

    mQuery =选择code,摘录,_id从codeS,其中PARENT_ID匹配+ PARENT_ID +;

    // startManagingCursor(C codeS);
    光标[] C = {cTitles,C codeS};
    光标光标=新MergeCursor(C);
    startManagingCursor(光标);

    返回游标;

}
 

解决方案

我不相信,捕捉从loader.loadInBackground光标()是你想要什么。 在实现loadInBackground()基本上是做一个查询并返回UI线程,这是你想要什么,以避免上的光标。

要谨慎,任何时候你都在等待UI线程上一个返回值。这应该是一个很好的指标,这是不是你想要的东西。

我所做的解决这个问题是要重新启动加载程序。 就我而言,我试图使用操作栏来搜索我的内容。 我的类扩展ListFragment和工具LoaderManager.LoaderCallbacks 容纳这个实现OnQueryTextListener,并呼吁到片段这里的活动是code,我做的片段。

 公共无效doSearch(查询字符串){
    束束=新包();
    bundle.putString(查询,查询);

    。getLoaderManager()restartLoader(LoaderMangerIdHelper.INVENTORY,捆绑,本);
}
 

请注意,您必须重新启动加载程序。装载机是由系统进行管理。这将导致您的onCreateLoader得到重新调用。所以,你必须检查查询字符串在那里设置你的选择。

  @覆盖
公共装载机<光标> onCreateLoader(INT ID,束束){
    串选择=someColumn =?;
    名单<字符串> selectionArgs两个=新的ArrayList<字符串>();
    selectionArgs.add(someArgs);

    如果(捆绑= NULL和放大器;!&安培; bundle.containsKey(查询)){
        选择+ =和columnTitle样?;
        selectionArgs.add(bundle.getString(查询)+%);
    }

    最终的String [] SELECTION_ARGS =新的String [selectionArgs.size()];
    selectionArgs.toArray(SELECTION_ARGS);

    mLoader =新CursorLoader(getActivity(),RoamPay.Product.CONTENT_URI,空,选择,
            SELECTION_ARGS,NULL);

    返回mLoader;
}
 
Android之cursorLoader进行数据异步加载

这在后台启动的cursorLoading。而回调应该是和往常一样。

  @覆盖
    公共无效onLoadFinished(装载机<光标>装载机,光标数据){
        //更换为新的光标(该框架将采取关闭的护理
        //老光标一次,我们返回。)
        mAdapter.swapCursor(数据);

        //现在应该显示的列表。
        如果(isResumed()){
            setListShown(真正的);
        } 其他 {
            setListShownNoAnimation(真正的);
        }
    }

    @覆盖
    公共无效onLoaderReset(装载机<光标>装载机){
        //这就是所谓的当提供给onLoadFinished一个光标()
        //以上即将被关闭。我们需要确保我们没有
        //不再使用它。
        mAdapter.swapCursor(空);
    }
 

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 and 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;

}

解决方案

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