使用 CursorAdapter 关闭 Cursor 会导致后台片段出现 StaleDataException
Closing Cursor causes StaleDataException on backgrounding fragment with CursorAdapter
这是对我在这里的问题的跟进:
响应解决了 "Cursor finalized without prior close" 警告,但它在非常特殊的情况下导致了 StaleDataException。
如果列表已经滚动,则此游标关闭...
Cursor cursor = null;
cursor = (Cursor) getListView().getItemAtPosition(n);
//do something
if(cursor != null) {
cursor.close();
}
和背景片段我得到以下错误:
09-15 21:16:58.240: E/test(21621): Exception
FATAL EXCEPTION: main
android.database.StaleDataException: Attempted to access a cursor after it has been closed.
at android.database.BulkCursorToCursorAdaptor.throwIfCursorIsClosed(BulkCursorToCursorAdaptor.java:64)
at android.database.BulkCursorToCursorAdaptor.getCount(BulkCursorToCursorAdaptor.java:70)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:196)
at android.database.CursorWrapper.moveToPosition(CursorWrapper.java:162)
at android.support.v4.widget.CursorAdapter.getItemId(CursorAdapter.java:225)
at android.widget.AbsListView.onSaveInstanceState(AbsListView.java:1782)
at android.view.View.dispatchSaveInstanceState(View.java:11950)
at android.view.ViewGroup.dispatchFreezeSelfOnly(ViewGroup.java:2685)
at android.widget.AdapterView.dispatchSaveInstanceState(AdapterView.java:782)
at android.view.ViewGroup.dispatchSaveInstanceState(ViewGroup.java:2671)
at android.view.View.saveHierarchyState(View.java:11933)
at android.support.v4.app.FragmentManagerImpl.saveFragmentViewState(FragmentManager.java:1608)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1004)
at android.support.v4.app.FragmentManagerImpl.removeFragment(FragmentManager.java:1212)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:639)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1478)
at android.support.v4.app.FragmentManagerImpl.run(FragmentManager.java:446)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4793)
这个问题似乎与一个类似的问题有关:Merging cursors during onLoadFinished() causes StaleDataException after rotation
但它涉及合并游标并建议使用 swapCursor,我不确定我将如何将其应用于这种情况。
我的想法是 getListView().getItemAtPosition(n)
必须返回对游标的引用而不是新游标,因此当 activity 处于后台并尝试在保存片段时访问现在关闭的游标声明它崩溃了。如前所述,它只会在滚动列表视图时崩溃,我不确定为什么会影响它。
如何在不导致崩溃的情况下正确关闭光标?
编辑代码以响应要求查看光标加载方式的评论:
String[] desired_columns = {
MediaStore.Audio.Media._ID, //this column is needed, even though it won't be displayed so the cursor can populate the listview
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.DURATION
};
String selectionStatement = MediaStore.Audio.Media.IS_MUSIC + " != ? AND " + MediaStore.Audio.Media.DURATION + " > ?";
String[] selectionArguments = new String[2];
selectionArguments[0] = "0";
selectionArguments[1] = "7000";
Cursor myCursor = getActivity().getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
desired_columns,
selectionStatement, //selection criteria
selectionArguments, //selection arguments like with SQL PDO use ? in criteria and put user input here to avoid sql injection
MediaStore.Audio.AudioColumns.ARTIST + " ASC"); //sort order of results
//moveToFirst() returns false if the cursor is empty
if (myCursor != null && myCursor.moveToFirst()) {
customCursorAdapter myCursorAdapter = new customCursorAdapter(getActivity(), myCursor, 0);
setListAdapter(myCursorAdapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
getListView().setSelector(R.drawable.list_selection_colouring);
}
试试这个
Cursor cursor = null;
try {
cursor = (Cursor) getListView().getItemAtPosition(n);
//do something
} finally {
if (cursor != null) {
cursor.close();
}
}
我找到了一个解决方案,它避免了已弃用的 manageQuery 并且也不使用 CursorLoaders。
解决方案是在 onDestroy() 中关闭游标。我尝试在 onPause 内关闭它,但这没有帮助。查看片段生命周期 http://developer.android.com/guide/components/fragments.html#Lifecycle
onDestroy 几乎是最后调用的方法,因此片段状态已经保存,可以安全地关闭游标。
这是我使用的代码:
@Override
public void onDestroy() {
super.onDestroy();
if (cursor != null) {
cursor.close();
}
}
这是对我在这里的问题的跟进:
响应解决了 "Cursor finalized without prior close" 警告,但它在非常特殊的情况下导致了 StaleDataException。
如果列表已经滚动,则此游标关闭...
Cursor cursor = null;
cursor = (Cursor) getListView().getItemAtPosition(n);
//do something
if(cursor != null) {
cursor.close();
}
和背景片段我得到以下错误:
09-15 21:16:58.240: E/test(21621): Exception
FATAL EXCEPTION: main
android.database.StaleDataException: Attempted to access a cursor after it has been closed.
at android.database.BulkCursorToCursorAdaptor.throwIfCursorIsClosed(BulkCursorToCursorAdaptor.java:64)
at android.database.BulkCursorToCursorAdaptor.getCount(BulkCursorToCursorAdaptor.java:70)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:196)
at android.database.CursorWrapper.moveToPosition(CursorWrapper.java:162)
at android.support.v4.widget.CursorAdapter.getItemId(CursorAdapter.java:225)
at android.widget.AbsListView.onSaveInstanceState(AbsListView.java:1782)
at android.view.View.dispatchSaveInstanceState(View.java:11950)
at android.view.ViewGroup.dispatchFreezeSelfOnly(ViewGroup.java:2685)
at android.widget.AdapterView.dispatchSaveInstanceState(AdapterView.java:782)
at android.view.ViewGroup.dispatchSaveInstanceState(ViewGroup.java:2671)
at android.view.View.saveHierarchyState(View.java:11933)
at android.support.v4.app.FragmentManagerImpl.saveFragmentViewState(FragmentManager.java:1608)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1004)
at android.support.v4.app.FragmentManagerImpl.removeFragment(FragmentManager.java:1212)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:639)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1478)
at android.support.v4.app.FragmentManagerImpl.run(FragmentManager.java:446)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4793)
这个问题似乎与一个类似的问题有关:Merging cursors during onLoadFinished() causes StaleDataException after rotation 但它涉及合并游标并建议使用 swapCursor,我不确定我将如何将其应用于这种情况。
我的想法是 getListView().getItemAtPosition(n)
必须返回对游标的引用而不是新游标,因此当 activity 处于后台并尝试在保存片段时访问现在关闭的游标声明它崩溃了。如前所述,它只会在滚动列表视图时崩溃,我不确定为什么会影响它。
如何在不导致崩溃的情况下正确关闭光标?
编辑代码以响应要求查看光标加载方式的评论:
String[] desired_columns = {
MediaStore.Audio.Media._ID, //this column is needed, even though it won't be displayed so the cursor can populate the listview
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.DURATION
};
String selectionStatement = MediaStore.Audio.Media.IS_MUSIC + " != ? AND " + MediaStore.Audio.Media.DURATION + " > ?";
String[] selectionArguments = new String[2];
selectionArguments[0] = "0";
selectionArguments[1] = "7000";
Cursor myCursor = getActivity().getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
desired_columns,
selectionStatement, //selection criteria
selectionArguments, //selection arguments like with SQL PDO use ? in criteria and put user input here to avoid sql injection
MediaStore.Audio.AudioColumns.ARTIST + " ASC"); //sort order of results
//moveToFirst() returns false if the cursor is empty
if (myCursor != null && myCursor.moveToFirst()) {
customCursorAdapter myCursorAdapter = new customCursorAdapter(getActivity(), myCursor, 0);
setListAdapter(myCursorAdapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
getListView().setSelector(R.drawable.list_selection_colouring);
}
试试这个
Cursor cursor = null;
try {
cursor = (Cursor) getListView().getItemAtPosition(n);
//do something
} finally {
if (cursor != null) {
cursor.close();
}
}
我找到了一个解决方案,它避免了已弃用的 manageQuery 并且也不使用 CursorLoaders。
解决方案是在 onDestroy() 中关闭游标。我尝试在 onPause 内关闭它,但这没有帮助。查看片段生命周期 http://developer.android.com/guide/components/fragments.html#Lifecycle onDestroy 几乎是最后调用的方法,因此片段状态已经保存,可以安全地关闭游标。
这是我使用的代码:
@Override
public void onDestroy() {
super.onDestroy();
if (cursor != null) {
cursor.close();
}
}