CursorLoader 和 CursorTreeAdapter

发布于 2024-12-02 13:48:40 字数 8893 浏览 2 评论 0原文

我正在尝试将 CursorLoader 与 CursorTreeAdapter 一起使用,但遇到了一个我无法弄清楚的问题。 (如果您有这方面的工作示例,请随意跳过其余部分并将其附在下面。我将非常感激) 第一次开群,一切正常。如果我随后关闭并重新打开该组,则会收到溢出错误。这是错误:

V/SpellBook(29520): Activity being created 
D/SpellBook(29520): onCreateLoader for id 123456 
V/SpellBook(29520): Resuming 
V/SpellBook(29520): Processing query for uri content://com.zalzala.spellbook.SpellProvider/levels/bard 
D/SpellBook(29520): onLoadFinished() for id 123456 
D/SpellBook(29520): onCreateLoader for id 3 
V/SpellBook(29520): Processing query for uri content://com.zalzala.spellbook.SpellProvider/class/bard/3 
D/SpellBook(29520): onLoadFinished() for id 3 

这里一切都很好。到目前为止,我已经打开了活动并打开了组号 3。 如果我关闭组 3 并再次打开它,会发生以下情况:

D/SpellBook(29520): onLoadFinished() for id 3 
D/SpellBook(29520): onLoadFinished() for id 3 
D/SpellBook(29520): onLoadFinished() for id 3 
D/SpellBook(29520): onLoadFinished() for id 3 
D/SpellBook(29520): onLoadFinished() for id 3 
(... and a lot more of these) 
    E/AndroidRuntime(29520): FATAL EXCEPTION: main 
E/AndroidRuntime(29520): java.lang.StackOverflowError 
E/AndroidRuntime(29520):    at java.util.HashMap.get(HashMap.java:302) 
E/AndroidRuntime(29520):    at android.database.sqlite.SQLiteCursor.getColumnIndex(SQLiteCursor.java:355)
E/AndroidRuntime(29520):    at android.database.CursorWrapper.getColumnIndex(CursorWrapper.java:67) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:216) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:159) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:183) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:1) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:413) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:547) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:217) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:159) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:183) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:1) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:413) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:547) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:217) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:159) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:183) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:1) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:413) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:547) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:217) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:159) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:183) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:1) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:413) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:547) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:217) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:159) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:183) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:1) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:413) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:547) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:217) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.ja 
W/ActivityManager( 6887):   Force finishing activity com.zalzala.spellbook/.SpellListView

因此,由于某种原因,在重新打开组时,子光标会一遍又一遍地调用 onLoadFinished() 。

这是我的加载器实现:

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // TODO Auto-generated method stub
        Log.d(Spellbook.TAG,"onCreateLoader for id "+id);
        if (id <123456){
            Uri spellUri = Uri.withAppendedPath(SpellProvider.CONTENT_URI, "class");
            spellUri = Uri.withAppendedPath(spellUri, mCLASS);
            spellUri = ContentUris.withAppendedId(spellUri, id);
            return new CursorLoader(getActivity(), spellUri, null, null, null, null);
        }else {
            //get group cursor
            Uri groupUri = Uri.withAppendedPath(SpellProvider.CONTENT_URI, "levels");
            groupUri = Uri.withAppendedPath(groupUri, mCLASS);
            return new CursorLoader(getActivity(), groupUri, null, null, null, null);
        }
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // TODO Auto-generated method stub
        int id = loader.getId();
        Log.d(Spellbook.TAG,"onLoadFinished() for id "+id);
        if (id < 123456){
            //child cursor
            ((CursorTreeAdapter) mAdapter).setChildrenCursor(id, data);
        } else {
            ((CursorTreeAdapter) mAdapter).setGroupCursor(data);
        }

    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // TODO Auto-generated method stub
        int id = loader.getId();
        Log.d(Spellbook.TAG,"onLoaderReset() for id "+id);
        if (id < 123456){
            //child cursor
            ((CursorTreeAdapter) mAdapter).setChildrenCursor(id, null);
        } else {
            ((CursorTreeAdapter) mAdapter).setGroupCursor(null);
        }

    }

我使用构造函数调用 CursorTreeAdapter,该构造函数将自动重新查询指定为 false。

    public class MyExpandableListAdapter extends CursorTreeAdapter {

        public MyExpandableListAdapter(Cursor cursor, Context context) {
            super(cursor, context, false); //do not auto requery. pretty sure CursorLoader needs this.
        }

        @Override
        protected Cursor getChildrenCursor(Cursor groupCursor) {
            // Given the group, we return a cursor for all the children within that group 
            int id = groupCursor.getInt(groupCursor.getColumnIndex(SpellDbAdapter.KEY_LEVEL));
            getLoaderManager().initLoader(id, null, ExpandableListCursorLoaderFragment.this);
            return null;
        }

感谢您的帮助!

I'm trying to use CursorLoader with a CursorTreeAdapter but am running into an issue I can't figure out. (If you have a working example of this, feel free to skip the rest and attach it below. I would be very thankful)
The first time I open a group, everything works fine. If I then close and re-open the group, I get an overflow error. Here is the error:

V/SpellBook(29520): Activity being created 
D/SpellBook(29520): onCreateLoader for id 123456 
V/SpellBook(29520): Resuming 
V/SpellBook(29520): Processing query for uri content://com.zalzala.spellbook.SpellProvider/levels/bard 
D/SpellBook(29520): onLoadFinished() for id 123456 
D/SpellBook(29520): onCreateLoader for id 3 
V/SpellBook(29520): Processing query for uri content://com.zalzala.spellbook.SpellProvider/class/bard/3 
D/SpellBook(29520): onLoadFinished() for id 3 

Everything is fine here. So far I've opened the activity and opened group number 3. Here is what happens if I close group 3 and open it again:

D/SpellBook(29520): onLoadFinished() for id 3 
D/SpellBook(29520): onLoadFinished() for id 3 
D/SpellBook(29520): onLoadFinished() for id 3 
D/SpellBook(29520): onLoadFinished() for id 3 
D/SpellBook(29520): onLoadFinished() for id 3 
(... and a lot more of these) 
    E/AndroidRuntime(29520): FATAL EXCEPTION: main 
E/AndroidRuntime(29520): java.lang.StackOverflowError 
E/AndroidRuntime(29520):    at java.util.HashMap.get(HashMap.java:302) 
E/AndroidRuntime(29520):    at android.database.sqlite.SQLiteCursor.getColumnIndex(SQLiteCursor.java:355)
E/AndroidRuntime(29520):    at android.database.CursorWrapper.getColumnIndex(CursorWrapper.java:67) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:216) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:159) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:183) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:1) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:413) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:547) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:217) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:159) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:183) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:1) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:413) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:547) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:217) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:159) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:183) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:1) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:413) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:547) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:217) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:159) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:183) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:1) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:413) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:547) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:217) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.java:106) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.setChildrenCursor(CursorTreeAdapter.java:159) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:183) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment.onLoadFinished(SpellListView.java:1) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:413) 
E/AndroidRuntime(29520):    at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:547) 
E/AndroidRuntime(29520):    at com.zalzala.spellbook.SpellListView$ExpandableListCursorLoaderFragment$MyExpandableListAdapter.getChildrenCursor(SpellListView.java:217) 
E/AndroidRuntime(29520):    at android.widget.CursorTreeAdapter.getChildrenCursorHelper(CursorTreeAdapter.ja 
W/ActivityManager( 6887):   Force finishing activity com.zalzala.spellbook/.SpellListView

So for some reason onLoadFinished() gets called over and over for the child cursor when re-opening a group.

Here is my loader implementation:

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // TODO Auto-generated method stub
        Log.d(Spellbook.TAG,"onCreateLoader for id "+id);
        if (id <123456){
            Uri spellUri = Uri.withAppendedPath(SpellProvider.CONTENT_URI, "class");
            spellUri = Uri.withAppendedPath(spellUri, mCLASS);
            spellUri = ContentUris.withAppendedId(spellUri, id);
            return new CursorLoader(getActivity(), spellUri, null, null, null, null);
        }else {
            //get group cursor
            Uri groupUri = Uri.withAppendedPath(SpellProvider.CONTENT_URI, "levels");
            groupUri = Uri.withAppendedPath(groupUri, mCLASS);
            return new CursorLoader(getActivity(), groupUri, null, null, null, null);
        }
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        // TODO Auto-generated method stub
        int id = loader.getId();
        Log.d(Spellbook.TAG,"onLoadFinished() for id "+id);
        if (id < 123456){
            //child cursor
            ((CursorTreeAdapter) mAdapter).setChildrenCursor(id, data);
        } else {
            ((CursorTreeAdapter) mAdapter).setGroupCursor(data);
        }

    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // TODO Auto-generated method stub
        int id = loader.getId();
        Log.d(Spellbook.TAG,"onLoaderReset() for id "+id);
        if (id < 123456){
            //child cursor
            ((CursorTreeAdapter) mAdapter).setChildrenCursor(id, null);
        } else {
            ((CursorTreeAdapter) mAdapter).setGroupCursor(null);
        }

    }

I call CursorTreeAdapter with the constructor which specifies auto requery as false.

    public class MyExpandableListAdapter extends CursorTreeAdapter {

        public MyExpandableListAdapter(Cursor cursor, Context context) {
            super(cursor, context, false); //do not auto requery. pretty sure CursorLoader needs this.
        }

        @Override
        protected Cursor getChildrenCursor(Cursor groupCursor) {
            // Given the group, we return a cursor for all the children within that group 
            int id = groupCursor.getInt(groupCursor.getColumnIndex(SpellDbAdapter.KEY_LEVEL));
            getLoaderManager().initLoader(id, null, ExpandableListCursorLoaderFragment.this);
            return null;
        }

Thanks for any help!

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

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

发布评论

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

评论(5

坦然微笑 2024-12-09 13:48:40

这是一个老问题,但仍然没有正确的答案(现在有了)。

MyExpandableListAdapter 有一个 getChildrenCursor(Cursor) 方法:

@Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
    int id = groupCursor.getInt(groupCursor.getColumnIndex(SpellDbAdapter.KEY_LEVEL));
    getLoaderManager().initLoader(id, null, ExpandableListCursorLoaderFragment.this);
    return null;
}

该方法通过 initLoader 调用启动 Loader。加载数据后,将调用 onLoadFinished 并设置子游标:

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // some code
    ((CursorTreeAdapter) mAdapter).setChildrenCursor(id, data);
    // some more code
}

CursorTreeAdapter.setChildrenCursor 方法如下所示:

public void setChildrenCursor(int groupPosition, Cursor childrenCursor) {
    MyCursorHelper childrenCursorHelper = getChildrenCursorHelper(groupPosition);
    childrenCursorHelper.changeCursor(childrenCursor, false);
}

它通过调用 CursorTreeAdapter.getChildrenCursorHelper 检索childrenCursorHelper:

synchronized MyCursorHelper getChildrenCursorHelper(int groupPosition, boolean requestCursor) {
    MyCursorHelper cursorHelper = mChildrenCursorHelpers.get(groupPosition);

    if (cursorHelper == null) {
        if (mGroupCursorHelper.moveTo(groupPosition) == null) return null;

        final Cursor cursor = getChildrenCursor(mGroupCursorHelper.getCursor());
        cursorHelper = new MyCursorHelper(cursor);
        mChildrenCursorHelpers.put(groupPosition, cursorHelper);
    }

    return cursorHelper;
}

在某些情况下,childrenCursorHelper 尚不存在,并且方法现在调用 getChildrenCursor(Cursor),这是启动整个调用链的方法。从逻辑上讲,我们会遇到 StackOverflowError。

这是 CursorTreeAdapter 类中的一个错误。虽然其他人建议改用 BaseExpandableAdapter,但我建议创建自定义 CursorTreeAdapter 类并进行必要的更改和修复。

通过更改 getChildrenCursorHelper 方法可以轻松修复 StackOverflowError。首先创建MyCursorHelper,将其添加到mChildrenCursorHelpers,然后如果retrieveChildCursor设置为true(新参数),则检索子光标。从 setChildrenCursor 调用该方法意味着我们传递 false 以避免陷入无限递归。

synchronized MyCursorHelper getChildrenCursorHelper(int groupPosition, boolean retrieveChildCursor) {
    MyCursorHelper cursorHelper = mChildrenCursorHelpers.get(groupPosition);

    if (cursorHelper == null && mGroupCursorHelper.moveTo(groupPosition) != null) {
        cursorHelper = new MyCursorHelper(null);
        mChildrenCursorHelpers.put(groupPosition, cursorHelper);

        if (retrieveChildCursor) {
            final Cursor cursor = getChildrenCursor(mGroupCursorHelper.getCursor());
            if (cursor != null) {
                cursorHelper.changeCursor(cursor, false);
            }
        }
    }

    return cursorHelper;
}

还要删除 MyCursorHelper.deactivate 方法中的代码,因为 CursorLoader 负责关闭过时的游标。

This is an old question but there's still no correct answer (well now there is).

The MyExpandableListAdapter has a getChildrenCursor(Cursor) method:

@Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
    int id = groupCursor.getInt(groupCursor.getColumnIndex(SpellDbAdapter.KEY_LEVEL));
    getLoaderManager().initLoader(id, null, ExpandableListCursorLoaderFragment.this);
    return null;
}

The method starts the Loader with the initLoader call. Once the data is loaded, onLoadFinished will be called and the children cursor is set:

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // some code
    ((CursorTreeAdapter) mAdapter).setChildrenCursor(id, data);
    // some more code
}

The CursorTreeAdapter.setChildrenCursor method goes like this:

public void setChildrenCursor(int groupPosition, Cursor childrenCursor) {
    MyCursorHelper childrenCursorHelper = getChildrenCursorHelper(groupPosition);
    childrenCursorHelper.changeCursor(childrenCursor, false);
}

It retrieves the childrenCursorHelper with a call to CursorTreeAdapter.getChildrenCursorHelper:

synchronized MyCursorHelper getChildrenCursorHelper(int groupPosition, boolean requestCursor) {
    MyCursorHelper cursorHelper = mChildrenCursorHelpers.get(groupPosition);

    if (cursorHelper == null) {
        if (mGroupCursorHelper.moveTo(groupPosition) == null) return null;

        final Cursor cursor = getChildrenCursor(mGroupCursorHelper.getCursor());
        cursorHelper = new MyCursorHelper(cursor);
        mChildrenCursorHelpers.put(groupPosition, cursorHelper);
    }

    return cursorHelper;
}

Under certain circumstances the childrenCursorHelper doesn't exist yet and the method now calls getChildrenCursor(Cursor) which is the method that started the whole call chain. Logically we will run into a StackOverflowError.

This is a bug in the CursorTreeAdapter class. While others recommend to use the BaseExpandableAdapter instead, I recommend to create a custom CursorTreeAdapter class and make the necessary changes and fixes.

The StackOverflowError can easily be fixed by changing the getChildrenCursorHelper method. Create the MyCursorHelper first, add it to mChildrenCursorHelpers and then retrieve the children cursor if retrieveChildCursor is set to true (new parameter). Calling the method from setChildrenCursor means we pass false to not get into the endless recursion.

synchronized MyCursorHelper getChildrenCursorHelper(int groupPosition, boolean retrieveChildCursor) {
    MyCursorHelper cursorHelper = mChildrenCursorHelpers.get(groupPosition);

    if (cursorHelper == null && mGroupCursorHelper.moveTo(groupPosition) != null) {
        cursorHelper = new MyCursorHelper(null);
        mChildrenCursorHelpers.put(groupPosition, cursorHelper);

        if (retrieveChildCursor) {
            final Cursor cursor = getChildrenCursor(mGroupCursorHelper.getCursor());
            if (cursor != null) {
                cursorHelper.changeCursor(cursor, false);
            }
        }
    }

    return cursorHelper;
}

Also remove the code in the MyCursorHelper.deactivate method since the CursorLoader takes care of closing obsolete cursors.

凹づ凸ル 2024-12-09 13:48:40

好吧,所以与 Google 的某人交谈,扩展列表可能早就应该被弃用了。如果您确实需要使用游标加载器和扩展列表,请扩展基本适配器。如果您确实不需要它,请继续而不使用游标加载器。

请随时纠正我:)

Ok, so talking to someone at Google, Expanded Lists should probably have been deprecated a long time ago. If you really need to use cursor loaders and expanded lists, extend the base adapter. If you don't really need it, go ahead and not use cursor loader.

Feel free to correct me :)

娇纵 2024-12-09 13:48:40

onGroupCollapsed() 上调用 destroyLoader()。但这并不能完全解决问题。查看 CursorTreeAdapter 实现,确保我不要将它与 CursorLoader 一起使用。

扩展BaseExpandableAdapter确实更好。这种方式可以避免不必要地(在使用加载器的情况下)使用内容观察器。在我的自定义适配器中,我将创建的加载器保留在稀疏数组中,并在组崩溃时销毁它们。效果很好:)

call destroyLoader() on onGroupCollapsed(). But it doesn't solve problem completely. Looking on CursorTreeAdapter realization make me sure to not use it with CursorLoader.

It's really better to extend BaseExpandableAdapter. This way allow to avoid unnecessary (in case of using loaders) usage of content observers. In my custom adapter i'm keep created loaders in sparse array and destroy them on group collapse. Works well :)

善良天后 2024-12-09 13:48:40

我认为当我们使用 initLoader 时,它会使堆栈变满,
尝试使用 restartLoader 代替。

@Override
    protected Cursor getChildrenCursor(Cursor groupCursor) {
        // TODO Auto-generated method stub          
        Bundle b = new Bundle();
        //b.putString("Artist", "\""+groupCursor.getString(groupCursor.getColumnIndex(artist.ARTIST))+"\"");
        b.putString("Artist", groupCursor.getString(groupCursor.getColumnIndex(artist.ARTIST)));
        getLoaderManager().restartLoader(groupCursor.getPosition(), b, MpArtist.this);
        return null;
    }

I think when we use initLoader, it will make stack full,
try using restartLoader instead.

@Override
    protected Cursor getChildrenCursor(Cursor groupCursor) {
        // TODO Auto-generated method stub          
        Bundle b = new Bundle();
        //b.putString("Artist", "\""+groupCursor.getString(groupCursor.getColumnIndex(artist.ARTIST))+"\"");
        b.putString("Artist", groupCursor.getString(groupCursor.getColumnIndex(artist.ARTIST)));
        getLoaderManager().restartLoader(groupCursor.getPosition(), b, MpArtist.this);
        return null;
    }
绳情 2024-12-09 13:48:40

试试这个:

@Override
public void onLoadFinished(Loader<Cursor> loader, final Cursor data) {
    // ...
    final int id = loader.getId();
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            ((CursorTreeAdapter) mAdapter).setChildrenCursor(id, data);
        }
    });
 }

Try this:

@Override
public void onLoadFinished(Loader<Cursor> loader, final Cursor data) {
    // ...
    final int id = loader.getId();
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            ((CursorTreeAdapter) mAdapter).setChildrenCursor(id, data);
        }
    });
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文