Android 游标装入器和游标转接器
我正在尝试将CursorLoader与CursorTreeAdapter一起使用,但遇到了一个无法解决的问题。(如果您有一个这样的工作示例,请跳过其余部分并将其附在下面。我将非常感谢) 我第一次组建团队时,一切都很顺利。如果随后关闭并重新打开组,则会出现溢出错误。以下是错误:Android 游标装入器和游标转接器,android,adapter,expandablelistview,android-cursorloader,Android,Adapter,Expandablelistview,Android Cursorloader,我正在尝试将CursorLoader与CursorTreeAdapter一起使用,但遇到了一个无法解决的问题。(如果您有一个这样的工作示例,请跳过其余部分并将其附在下面。我将非常感谢) 我第一次组建团队时,一切都很顺利。如果随后关闭并重新打开组,则会出现溢出错误。以下是错误: V/SpellBook(29520): Activity being created D/SpellBook(29520): onCreateLoader for id 123456 V/SpellBook(29520
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);
}
}
谢谢你的帮助 好吧,跟谷歌的某个人说,扩展列表可能很久以前就应该被弃用了。如果确实需要使用光标加载器和扩展列表,请扩展基本适配器。如果您真的不需要它,请不要使用游标加载器 请随时纠正我:)在
onGroupCollapsed()
上调用destroyLoader()
。但这并不能完全解决问题。查看CursorTreeAdapter
实现,确保不要将其与CursorLoader
一起使用
扩展
BaseExpandableAdapter
确实更好。这样可以避免不必要的(在使用加载器的情况下)使用内容观察者。在我的自定义适配器中,我将创建的加载程序保持在稀疏数组中,并在组崩溃时销毁它们。工作良好:)我认为当我们使用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;
}
试试这个:
@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);
}
});
}
@覆盖
public void onLoadFinished(加载程序,最终光标数据){
// ...
final int id=loader.getId();
new Handler().post(new Runnable()){
@凌驾
公开募捐{
((CursorTreeAdapter)mAdapter).setChildrenCursor(id,数据);
}
});
}
这是一个老问题,但仍然没有正确答案(现在有了)
MyExpandableListAdapter有一个getChildrenCursor(游标)方法:
该方法使用initLoader调用启动加载程序。加载数据后,将调用onLoadFinished并设置子光标:
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// some code
((CursorTreeAdapter) mAdapter).setChildrenCursor(id, data);
// some more code
}
它通过调用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),这是启动整个调用链的方法。从逻辑上讲,我们将遇到StackOverflower错误
这是CursorTreeAdapter类中的错误。虽然其他人建议改用BaseExpandableAdapter,但我建议创建一个自定义的CursorTreeAdapter类,并进行必要的更改和修复
StackOverflowerError可以通过更改getChildrenCursorHelper方法轻松修复。首先创建MyCursorHelper,将其添加到McChildrenCursorHelpers,然后在retrieveChildCursor设置为true(新参数)时检索子光标。从setChildrencersor调用该方法意味着传递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方法中的代码,因为游标加载程序负责关闭过时的游标。ExpandableList不推荐使用?我不这么认为,也许你说的是CursorTreeAdapter…但这不是违背了使用加载器的初衷吗?忘了我的答案吧。也许我应该删除它。查看CursorTreeAdapter实现,确保不要将其与CursorLoader一起使用。扩展基本可扩展适配器确实更好。实际上,这是一个非常好的建议。扩展基本可扩展适配器可能是一种方法。而且这种方法可以避免不必要的(在使用加载程序的情况下)使用内容观察者。在我的自定义适配器中,我将创建的加载程序保持在稀疏阵列中,并在组崩溃时销毁它们。很好:)酷。如果您不介意的话,请更新您的答案,我会接受。我尝试了类似的实现,但无法使其正常工作。我不是子类化CursorTreeAdapter,而是子类化SimpleCursorTreeAdapter。groupCursor加载良好,我可以看到所有组,但是当我单击其中一个组时,它调用getChildrenCursor()子例程,该子例程返回null。我得到一个空指针表达式错误。你遇到过这个问题吗?听起来这更像是你如何得到孩子的问题。您能验证获取子游标的调用在测试中是否有效吗?我发现问题不在于getChildrenCursor()子例程,而在于对setChildrenCursor()子例程的调用。因此,在我的onLoadFinished()方法中,我获取加载程序的id。如果它是一个子游标,那么我已经将setChildrenCursor放在一个try-catch块try{mAdapter.setChildrenCursor(id,data);}catch(NullPointerException e){Log.w(“标记”,“适配器已过期,请在下一个查询中重试:“+e.getMessage());}现在,当抛出空指针异常时,我正在捕获它。但是,只有一些组被展开以显示子组。我在这里做了类似的事情,我在SDK示例中遵循了这个文件
ApiDemos/src/com/example/android/api/view/ExpandableList2.java
,我的列表运行良好…
public void setChildrenCursor(int groupPosition, Cursor childrenCursor) {
MyCursorHelper childrenCursorHelper = getChildrenCursorHelper(groupPosition);
childrenCursorHelper.changeCursor(childrenCursor, false);
}
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;
}
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;
}