2011-11-29 64 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。

相關問題