关闭游标导致StaleDataException与CursorAdapter的一个后台片段 [英] Closing Cursor causes StaleDataException on backgrounding fragment with CursorAdapter

查看:936
本文介绍了关闭游标导致StaleDataException与CursorAdapter的一个后台片段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个跟进在这里我的问题:
<一href=\"http://stackoverflow.com/questions/32201617/how-to-close-a-cursor-used-in-a-for-loop/32201879#32201879\">How至收盘,用于循环光标

的答复解决了光标敲定,恕不另行关闭的警告,但它已经在一个非常特殊的情况引起了StaleDataException。

如果列表中已滚动,这个光标关闭...

 光标指针= NULL;
光标=(光标)getListView()getItemAtPosition(N)。
//做一点事
如果(指针!= NULL){
    cursor.close();
}

和片段后台运行,我得到了以下错误:

  09-15 21:16:58.240:E /测试(21621):异常
 致命异常:主要
 android.database.StaleDataException:试图它已被关闭之后访问光标。
    在android.database.BulkCursorToCursorAdaptor.throwIfCursorIsClosed(BulkCursorToCursorAdaptor.java:64)
    在android.database.BulkCursorToCursorAdaptor.getCount(BulkCursorToCursorAdaptor.java:70)
    在android.database.AbstractCursor.moveToPosition(AbstractCursor.java:196)
    在android.database.CursorWrapper.moveToPosition(CursorWrapper.java:162)
    在android.support.v4.widget.CursorAdapter.getItemId(CursorAdapter.java:225)
    在android.widget.AbsListView.onSaveInstanceState(AbsListView.java:1782)
    在android.view.View.dispatchSaveInstanceState(View.java:11950)
    在android.view.ViewGroup.dispatchFreezeSelfOnly(ViewGroup.java:2685)
    在android.widget.AdapterView.dispatchSaveInstanceState(AdapterView.java:782)
    在android.view.ViewGroup.dispatchSaveInstanceState(ViewGroup.java:2671)
    在android.view.View.saveHierarchyState(View.java:11933)
    在android.support.v4.app.FragmentManagerImpl.saveFragmentViewState(FragmentManager.java:1608)
    在android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1004)
    在android.support.v4.app.FragmentManagerImpl.removeFragment(FragmentManager.java:1212)
    在android.support.v4.app.BackStackRecord.run(BackStackRecord.java:639)
    在android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1478)
    在android.support.v4.app.FragmentManagerImpl $ 1.run(FragmentManager.java:446)
    在android.os.Handler.handleCallback(Handler.java:615)
    在android.os.Handler.dispatchMessage(Handler.java:92)
    在android.os.Looper.loop(Looper.java:137)
    在android.app.ActivityThread.main(ActivityThread.java:4793)

此问题似乎涉及到一个类似的问题:<一href=\"http://stackoverflow.com/questions/16392692/merging-cursors-during-onloadfinished-causes-staledataexception-after-rotation\">Merging onLoadFinished()期间光标转动后引起StaleDataException
但它涉及到合并光标和使用swapCursor建议,我不知道我怎么会是适用于这种情况。

我的想法是, getListView()。getItemAtPosition(N)必须返回游标的引用,而不是一个新的光标,所以当该活动后台运行,并尝试访问已经结束,而光标拯救崩溃的碎片状态。正如前面提到的,它只有崩溃,如果列表视图中已滚动,我不知道为什么应该对其产生影响。

我如何正确地关闭游标不会导致飞机坠毁?

编辑code回应评论要求见光标的加载方式:

 的String [] = desired_columns {
                MediaStore.Audio.Media._ID,//需要此列中,即使它不会被显示,以便光标能够填充列表视图
                MediaStore.Audio.Media.ARTIST,
                MediaStore.Audio.Media.ALBUM,
                MediaStore.Audio.Media.TITLE,
                MediaStore.Audio.Media.DURATION                };        字符串selectionStatement = MediaStore.Audio.Media.IS_MUSIC + + MediaStore.Audio.Media.DURATION +&GT?;= AND!?        的String [] = selectionArguments新的String [2];
        selectionArguments [0] =0;
        selectionArguments [1] =7000;        光标myCursor = getActivity()。getContentResolver()查询(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                                                                    desired_columns,
                                                                    selectionStatement,//选择标准
                                                                    selectionArguments,//选择论像SQL PDO使用?在标准和把用户输入的位置,以避免SQL注入
                                                                    MediaStore.Audio.AudioColumns.ARTIST +ASC); //结果的排序顺序
        如果光标空// moveToFirst()返回false
        如果(myCursor =空&放大器;!&放大器; myCursor.moveToFirst()){
            customCursorAdapter myCursorAdapter =新customCursorAdapter(getActivity(),myCursor,0);            setListAdapter(myCursorAdapter);            。getListView()setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
            。getListView()setSelector(R.drawable.list_selection_colouring);
        }


解决方案

我发现它避免了去precated manageQuery,也没有使用CursorLoaders的解决方案。

解决的办法是关闭游标内的onDestroy()。我试图内的onPause关闭它,但这并没有帮助。纵观片段生命周期 http://developer.android.com/guide/components/ fragments.html#生命周期
的onDestroy几乎是这么叫的片段国家将已经被保存了最后一个方法,使其安全地关闭游标。

下面是code我用:

  @覆盖
公共无效的onDestroy(){
   super.onDestroy();
   如果(指针!= NULL){
      cursor.close();
   }
}

This is a follow up to my question here: How to close a cursor used in a for loop

The responses solved the "Cursor finalized without prior close" warning but it has caused a StaleDataException in a very particular situation.

If the list has been scrolled, this cursor closed...

Cursor cursor = null;
cursor = (Cursor) getListView().getItemAtPosition(n);
//do something
if(cursor != null) {
    cursor.close();
}

and the fragment backgrounded I get the following error:

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$1.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)

This question seems to relate to a similar issue: Merging cursors during onLoadFinished() causes StaleDataException after rotation but it relates to merging cursors and suggests using swapCursor, I'm not sure how I would apply that to this situation.

My thoughts are that getListView().getItemAtPosition(n) must be returning a reference to the cursor rather than a new cursor and so when the activity is backgrounded and tries to access the now closed cursor whilst saving the fragment state it crashes. As mentioned earlier, it only crashes if the list view has been scrolled, I'm not sure why that should affect it.

How do I correctly close the cursor without causing a crash?

EDIT code in response to a comment asking to see how the cursor was loaded:

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

解决方案

I found a solution which avoids the deprecated manageQuery and also doesn't use CursorLoaders.

The solution was to close the cursor within onDestroy(). I tried closing it within onPause but this didn't help. Looking at the fragment lifecycle http://developer.android.com/guide/components/fragments.html#Lifecycle onDestroy is almost the last method called so the fragments state will already have been saved, making it safe to close the cursor.

Here is the code I used:

@Override
public void onDestroy() {
   super.onDestroy();
   if (cursor != null) {
      cursor.close();
   }
}

这篇关于关闭游标导致StaleDataException与CursorAdapter的一个后台片段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆