Android兼容性库游标加载程序:java.lang.IllegalStateException:游标已关闭

Android兼容性库游标加载程序:java.lang.IllegalStateException:游标已关闭,android,Android,我目前正在Android兼容性库的一个片段中使用游标加载程序。 几乎每一次,在Droid2上(我无法在NexusOne或Sensation上重现),似乎光标关闭得太快,这导致了各种错误。不幸的是,这些跟踪在我的代码中没有任何帮助(因为问题是为什么光标会被关闭,而不是当Android注意到时),所以我真的很难找出哪里出了问题。还有其他人遇到过这个问题吗?(或者对可能发生的事情有想法) 一些堆栈跟踪: java.lang.IllegalStateException: Cursor is closed

我目前正在Android兼容性库的一个片段中使用游标加载程序。 几乎每一次,在Droid2上(我无法在NexusOne或Sensation上重现),似乎光标关闭得太快,这导致了各种错误。不幸的是,这些跟踪在我的代码中没有任何帮助(因为问题是为什么光标会被关闭,而不是当Android注意到时),所以我真的很难找出哪里出了问题。还有其他人遇到过这个问题吗?(或者对可能发生的事情有想法)

一些堆栈跟踪:

java.lang.IllegalStateException: Cursor is closed                                    
    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:278)         
    at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:255)             
    at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:187)        
    at android.database.CursorWrapper.moveToPosition(CursorWrapper.java:187)          
    at android.support.v4.widget.CursorAdapter.getItemId(CursorAdapter.java:226)      
    at android.widget.AbsListView$PerformClick.run(AbsListView.java:1721)             
    at android.os.Handler.handleCallback(Handler.java:587)                            
    at android.os.Handler.dispatchMessage(Handler.java:92)                            
    at android.os.Looper.loop(Looper.java:143)                                        
    at android.app.ActivityThread.main(ActivityThread.java:4717)                      
    at java.lang.reflect.Method.invokeNative(Native Method)                           
    at java.lang.reflect.Method.invoke(Method.java:521)                               
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)                   
    at dalvik.system.NativeStart.main(Native Method)           

java.lang.IllegalStateException: Cursor is closed                                                          
    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:278)                               
    at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:255)                                   
    at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:187)                              
    at android.database.CursorWrapper.moveToPosition(CursorWrapper.java:187)                                
    at android.support.v4.widget.CursorAdapter.getItemId(CursorAdapter.java:226)                            
    at android.widget.AdapterView.getItemIdAtPosition(AdapterView.java:745)                                 
    at android.widget.AdapterView.setSelectedPositionInt(AdapterView.java:1081)                             
    at android.widget.AbsListView.onTouchEvent(AbsListView.java:2207)                                       
    at android.widget.ListView.onTouchEvent(ListView.java:3377)                                             
    at android.view.View.dispatchTouchEvent(View.java:3766)                                                 
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:897)                                        
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)                                        
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)                                        
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)                                        
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)                                        
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:936)                                        
    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1800)
    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1140)          
    at android.app.Activity.dispatchTouchEvent(Activity.java:2105)                                          
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1784)     
    at android.view.ViewRoot.handleMessage(ViewRoot.java:1794)                                              
    at android.os.Handler.dispatchMessage(Handler.java:99)                                                  
    at android.os.Looper.loop(Looper.java:143)                                                              
    at android.app.ActivityThread.main(ActivityThread.java:4717)                                            
    at java.lang.reflect.Method.invokeNative(Native Method)                                                 
    at java.lang.reflect.Method.invoke(Method.java:521)                                                     
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)                      
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)                                         
    at dalvik.system.NativeStart.main(Native Method)     

java.lang.RuntimeException: Unable to pause activity : java.lang.IllegalStateException: Cursor is closed
    at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3438)                         
    at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3395)                         
    at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3378)                          
    at android.app.ActivityThread.access$2700(ActivityThread.java:129)                                   
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2124)                              
    at android.os.Handler.dispatchMessage(Handler.java:99)                                               
    at android.os.Looper.loop(Looper.java:143)                                                           
    at android.app.ActivityThread.main(ActivityThread.java:4717)                                         
    at java.lang.reflect.Method.invokeNative(Native Method)                                              
    at java.lang.reflect.Method.invoke(Method.java:521)                                                  
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)                   
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)                                      
    at dalvik.system.NativeStart.main(Native Method)                                                     
Caused by: java.lang.IllegalStateException: Cursor is closed                                            
    at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:278)                            
    at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:255)                                
    at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:187)                           
    at android.database.CursorWrapper.moveToPosition(CursorWrapper.java:187)                             
    at android.support.v4.widget.CursorAdapter.getItemId(CursorAdapter.java:226)                         
    at android.widget.AbsListView.onSaveInstanceState(AbsListView.java:910)                              
    at android.widget.ListView.onSaveInstanceState(ListView.java:3687)                                   
    at android.view.View.dispatchSaveInstanceState(View.java:6070)                                       
    at android.view.ViewGroup.dispatchFreezeSelfOnly(ViewGroup.java:1197)                                
    at android.widget.AdapterView.dispatchSaveInstanceState(AdapterView.java:759)                        
    at android.view.ViewGroup.dispatchSaveInstanceState(ViewGroup.java:1184)                             
    at android.view.View.saveHierarchyState(View.java:6053)                                              
    at android.support.v4.app.FragmentManagerImpl.saveFragmentViewState(FragmentManager.java:1387)       
    at android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.java:1439)                
    at android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.java:468)            
    at android.app.Activity.performSaveInstanceState(Activity.java:1040)                                 
    at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1180)            
    at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3420)                         
    ... 12 more                                                                         
对于好的度量,我的代码中至少有一行:

android.database.StaleDataException: Access closed cursor                                   
    at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:217)
    at android.database.AbstractWindowedCursor.getBlob(AbstractWindowedCursor.java:27)       
    at android.database.CursorWrapper.getBlob(CursorWrapper.java:143)                        
    at android.database.CursorWrapper.getBlob(CursorWrapper.java:143)                        
    at com.testapp.TestFragment$1.setViewValue(TestFragment.java:84)                         
    at android.support.v4.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:131)  
    at android.support.v4.widget.CursorAdapter.getView(CursorAdapter.java:257)               
    at android.widget.AbsListView.obtainView(AbsListView.java:1319)                          
    at android.widget.ListView.makeAndAddView(ListView.java:1789)                            
    at android.widget.ListView.fillDown(ListView.java:656)                                   
    at android.widget.ListView.fillSpecific(ListView.java:1342)                              
    at android.widget.ListView.layoutChildren(ListView.java:1616)                            
    at android.widget.AbsListView.onLayout(AbsListView.java:1172)                            
    at android.view.View.layout(View.java:7037)                                              
    at android.widget.FrameLayout.onLayout(FrameLayout.java:333)                             
    at android.view.View.layout(View.java:7037)                                              
    at android.widget.FrameLayout.onLayout(FrameLayout.java:333)                             
    at android.view.View.layout(View.java:7037)                                              
    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1249)                     
    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1125)                    
    at android.widget.LinearLayout.onLayout(LinearLayout.java:1042)                          
    at android.view.View.layout(View.java:7037)                                              
    at android.widget.FrameLayout.onLayout(FrameLayout.java:333)                             
    at android.view.View.layout(View.java:7037)                                              
    at android.widget.FrameLayout.onLayout(FrameLayout.java:333)                             
    at android.view.View.layout(View.java:7037)                                              
    at android.view.ViewRoot.performTraversals(ViewRoot.java:1054)                           
    at android.view.ViewRoot.handleMessage(ViewRoot.java:1736)                               
    at android.os.Handler.dispatchMessage(Handler.java:99)                                   
    at android.os.Looper.loop(Looper.java:143)                                               
    at android.app.ActivityThread.main(ActivityThread.java:4717)                             
    at java.lang.reflect.Method.invokeNative(Native Method)                                  
    at java.lang.reflect.Method.invoke(Method.java:521)                                      
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)       
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)                          
    at dalvik.system.NativeStart.main(Native Method)                                         

更新:已修复,请参见下面的我的答案

我不知道问题出在哪里,但这可能有助于您确定问题所在

像这样创建一个
LoggedCursor
,并设置游标工厂,以便查询提供LoggedCursor:

class LoggedCursor extends SQLiteCursor {
    @Override
    public void close() {
        Log.d(TAG, "Cursor closed by:", new RuntimeException("Stack trace"));
        super.close();
    }
}
创建
RuntimeException
只是为了方便地记录堆栈跟踪,而不是为了抛出堆栈跟踪。当光标关闭时,您将在日志中看到跟踪


希望这有助于确定何时以及由谁关闭

我根据JBM的建议添加了日志记录,并发现以下内容:

我在代码中使用了CursorWrapper的一个子类。 在Droid2上,有人向CursorWrapper添加了一个终结器,它关闭了底层游标。这意味着每当我们的包装器被垃圾回收时,游标就被关闭。此终结器不存在于其他手机或Android源代码中。我猜有人认为他们很聪明

通过重写游标包装器中的终结器修复

protected void finalize() throws Throwable {
    // Do not remove this empty method. It is designed to prevent calls to super.
    // Fixes bug on Droid 2, where CursorWrapper finalizer closes the Cursor!
}

你自己关闭游标吗?不,我自己没有打开或关闭任何游标。这也是我最初的想法,但我也没有实际构建游标。光标的整个生命周期都由CursorLoader处理(这意味着我没有办法使用工厂)
CursorLoader
内部调用
ContentResolver.query(…)
,这反过来会获取与URI匹配的
IContentProvider
,并对其执行
query(…)
。我不知道您的URI是什么,但我认为可以在启动加载程序之前获取URI的内容提供者,使用游标工厂进行设置,然后启动加载程序。或者类似的。。尝试在调试模式下获取URI的内容提供程序,找出返回的类,以便查看源代码。感谢您的帮助!我发现了这项技术的潜在问题,并将其作为一个答案发布。我没有使用CursorWrapper,但在Access关闭Cursor的情况下,我每天仍会收到大约4份崩溃报告,这些报告来自不同的手机。我无法在Nexus或Droid 1上复制它。您能否提供更多关于如何使用CursorWrapper的详细信息。我需要扩展游标加载程序吗?