Reputation: 7318
I guess I do not understand correctly how to use CursorTreeAdapter.setChildrenCursor()
, because I get a StackOverflowError
, because of what seems like a loop in my LogCat.
The pattern in the loop is:
getChildrenCursor()
restarts a Loader
CursorTreeAdapter.setChildrenCursor()
calls CursorTreeAdapter.getChildrenCursorHelper()
, which getChildrenCursor
. I suspect that Android's source code may exhibit incorrect behaviour (see final code snippet).
Here's the relevant methods in my code:
CursorTreeAdapter
:
/**
* Return null, but set off a Loader that will set the Cursor after asynchronous loading
**/
@Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
getLoaderManager().initLoader(groupCursor.getInt(0), null, CollectionsMasterFragment.this);
return null;
}
LoaderCallbacks
:
@Override
public void onLoadFinished(android.support.v4.content.Loader loader, Cursor cursor) {
d("onLoadFinished with "
+ cursor.getCount() + " elements");
// Set children cursor to correct group
switch (loader.getId()) {
case POS_0:
mCollectionsAdapter.setChildrenCursor(POS_0, cursor);
break;
case POS_1:
mCollectionsAdapter.setChildrenCursor(POS_1, cursor);
break;
default:
throw new IllegalArgumentException(
"Could not handle loader id " + loader.getId());
}
}
@Override
public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
switch (id) {
case POS_0:
d("Creating new dossiers loader");
return new Model.Dossier.Loader(getActivity());
case POS_1:
d("Creating new bundles loader");
return new Model.Bundle.Loader(getActivity());
default:
throw new IllegalArgumentException(
"Could not handle loader id " + id);
}
}
Here's Android 4.4's code for CursorTreeAdapter
:
/**
* Sets the children Cursor for a particular group. If there is an existing cursor
* it will be closed.
* <p>
* This is useful when asynchronously querying to prevent blocking the UI.
*
* @param groupPosition The group whose children are being set via this Cursor.
* @param childrenCursor The Cursor that contains the children of the group.
*/
public void setChildrenCursor(int groupPosition, Cursor childrenCursor) {
/*
* Don't request a cursor from the subclass, instead we will be setting
* the cursor ourselves.
*/
MyCursorHelper childrenCursorHelper = getChildrenCursorHelper(groupPosition, false);
/*
* Don't release any cursor since we know exactly what data is changing
* (this cursor, which is still valid).
*/
childrenCursorHelper.changeCursor(childrenCursor, false);
}
/**
* Gets the cursor helper for the children in the given group.
*
* @param groupPosition The group whose children will be returned
* @param requestCursor Whether to request a Cursor via
* {@link #getChildrenCursor(Cursor)} (true), or to assume a call
* to {@link #setChildrenCursor(int, Cursor)} will happen shortly
* (false).
* @return The cursor helper for the children of the given group
*/
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;
}
As you can see, the parameter requestCursor
for getChildrenCursorHelper
is ignored, so that getChildrenCursor
is called again!
What's up with this? Is this a bug? Shouldn't setChildrenCursor
just perform childrenCursorHelper = new MyCursorHelper(childrenCursor)
, instead of asking the adapter for the childrenCursor?!
Upvotes: 2
Views: 637
Reputation: 696
I am struggling also trying to populate an expandable listview from a loader, however I think part of your problem has to do with the fact you must implement multiple loaders for each type or schema, see if this link helps*Set multiple cursor loaders with multiple adapters - Android*
Upvotes: 1