2011-11-29 108 views
0

在我的活动中,我有2个CursorLoader和2个带有OnClickListener的TextView,它调用setScreen()方法。点击Textviews有时我也出错CursorLoader和完成游标尚未停用或关闭错误

11-29 15:27:26.045: INFO/dalvikvm(1223): Ljava/lang/IllegalStateException;: Finalizing cursor [email protected] on MAIN_TABLE that has not been deactivated or closed 
11-29 15:27:26.045: INFO/dalvikvm(1223):  at android.database.sqlite.SQLiteCursor.finalize(SQLiteCursor.java:596) 
11-29 15:27:26.045: INFO/dalvikvm(1223):  at dalvik.system.NativeStart.run(Native Method) 
11-29 15:27:26.065: INFO/dalvikvm(1223): Uncaught exception thrown by finalizer (will be discarded): 

的完整源代码

public class ActivityMatchesList extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor> { 
    private MyAdapter1 mAdapter1; 
    private MyAdapter2 mAdapter2; 
    private int mTab; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     /** Cursor Loader */ 
     getSupportLoaderManager().initLoader(1, null, this); 
     getSupportLoaderManager().initLoader(2, null, this); 
     /** set content view */ 
     setContentView(R.layout.main_list); 
     View vv = new View(this); 
     LinearLayout ll = (LinearLayout) findViewById(R.id.boxRanking); 
     vv = View.inflate(this, R.layout.tab_ranking, null); 
     ll.addView(vv, new LinearLayout.LayoutParams(ll.getLayoutParams().width, ll.getLayoutParams().height)); 
     /** set colors */ 
     ListView lvLive = (ListView)findViewById(R.id.matchListList); 
     ListView lvLeagueMatches = (ListView) findViewById(R.id.listLeagueMatches); 
     /** create and set Adapters */ 
     mAdapter1 =  new MyAdapter1(
      this, 
      R.layout.main_list_row, 
      null, 
      0); 
     mAdapter2 = new MyAdapter2(
      this, 
      R.layout.list_ran_row, 
      null, 
      0); 
     lvLive.setAdapter(mAdapter1); 
     lvLeagueMatches.setAdapter(mAdapter2);   

     /** listener */ 
     TextView tabLive = (TextView) findViewById(R.id.tab_main); 
     TextView tabRank = (TextView) findViewById(R.id.tab_ran); 
     tabLive.setOnClickListener(onClickListenerTab); 
     tabRank.setOnClickListener(onClickListenerTab); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     setScreen(); 
    } 

    private void setScreen() { 
     if (mTab!=Constants.Tab.TAB_2) mTab=Constants.Tab.TAB_1; 
     LinearLayout llRanking = (LinearLayout) findViewById(R.id.boxRanking); 
     ListView lvLive = (ListView)findViewById(R.id.matchListList); 
     switch (mTab){ 
      case Constants.Tab.TAB_1: 
       llRanking.setVisibility(View.GONE); 
       lvLive.setVisibility(View.VISIBLE); 
       break; 
      case Constants.Tab.TAB_2: 
       llRanking.setVisibility(View.VISIBLE); 
       lvLive.setVisibility(View.GONE); 
       break; 
     } 
     getContentResolver().notifyChange(MyProvider.CONTENT_URI, null); 
    } 

    private OnClickListener onClickListenerTab = new OnClickListener() { 
     public void onClick(final View v) { 
      int mNewTab; 
      if(v.getId()==R.id.tab_ran){ 
       mNewTab = Constants.Tab.TAB_2; 
      } else { 
       mNewTab = Constants.Tab.TAB_1; 
      } 
      if (mTab != mNewTab) { 
       mTab = mNewTab; 
       setScreen(); 
      } 
     } 
    }; 

    @Override 
    public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
     switch (id){ 
     case 1: 
      CursorLoader cursorLoaderLive = new CursorLoader(
       this, 
       MyProvider.CONTENT_URI_MAIN, 
       null, 
       null, 
       null, 
       "MatchDateYear, MatchDateMonth, MatchDateDay, MatchHour, MatchMinute"); 
      return cursorLoaderLive; 
     case 2: 
      CursorLoader cursorLoaderRankingLeague = new CursorLoader(
       this, 
       MyProvider.CONTENT_URI_RAN, 
       null, 
       "Round=3 AND IsMatch=1", 
       null, 
       null); 
      return cursorLoaderRankingLeague; 
     default: 
      return null; 
     } 
    } 

    @Override 
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 
     switch (loader.getId()){ 
     case 1: 
      mAdapter1.swapCursor(cursor); 
      break; 
     case 2: 
      mAdapter2.swapCursor(cursor); 
      break; 
     } 
    } 

    @Override 
    public void onLoaderReset(Loader<Cursor> loader) { 
     switch (loader.getId()){ 
     case 1: 
      mAdapter1.swapCursor(null); 
      break; 
     case 2: 
      mAdapter2.swapCursor(null); 
      break; 
     } 
    } 
} 

为什么CursorLoader给出了这样的错误?我读过CursorLoader应该管理光标并在必要时关闭它。

回答

1

不知道是否有任何这是关系到你的问题,但在这里有云:

  1. 我不会把getSupportLoaderManager().initLoader()创建您的适配器之前。也许它有效,但如果在创建适配器之前调用onLoadFinished(),则在我看来,它可能会导致问题。

  2. 你为什么在你的setScreen()方法中打电话getContentResolver().notifyChange()?据我所知,notifyChange()是用于通知内容提供商中的数据已更改,但它并不像我在改变任何东西。从我对内容提供者的有限使用中,我只在内容提供者类本身中调用ContentResolver.notifyChange()。在这里看到它使用了一个例子:http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/NotePadProvider.html

  3. 这真的是吹毛求疵,但在onCreateLoader()你也许可以做这样的事情:

    return new CursorLoader(
    ,而不是创建未使用的引用。

  4. 最后,为了找到真正的问题,我唯一一次看到错误是当我有一个打开的光标,我还没有关闭。由于CursorLoader处理游标生命周期,因此我希望确保应用程序中没有任何其他位置存在打开的游标,例如调用getContentResolver().query()或直接查询数据库。

  5. 如果以上都没有工作,也许你可以将你用单独的CursorLoaders处理的数据拆分成单独的CursorProviders。

相关问题