在我的活动中,我有2个CursorLoader和2个带有OnClickListener的TextView,它调用setScreen()方法。有时单击Textviews我有错误
11-29 15:27:26.045: INFO/dalvikvm(1223): Ljava/lang/IllegalStateException;: Finalizing cursor android.database.sqlite.SQLiteCursor@43c02e18 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应该管理光标并在必要时关闭它。
答案 0 :(得分:1)
不确定这是否与您的问题有关,但请注意:
在创建适配器之前,我不会调用getSupportLoaderManager().initLoader()
。也许它有效,但如果在创建适配器之前调用onLoadFinished()
,我觉得它可能会导致问题。
为什么要在getContentResolver().notifyChange()
方法中调用setScreen()
?据我所知,notifyChange()用于通知内容提供商中的数据已更改,但它并不像我在改变任何内容。从我对内容提供商的有限使用来看,我只在内容提供者类本身中调用ContentResolver.notifyChange()
。请参阅此处的示例:http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/NotePadProvider.html
这真的很挑剔,但在onCreateLoader()
你可以这样做:
return new CursorLoader(而不是创建未使用的引用。
最后,为了得到实际的问题,我唯一一次看到这个错误就是当我有一个我没有关闭的打开游标时。由于CursorLoader处理游标生命周期,因此我希望确保您的应用程序中没有其他任何地方可以打开游标,例如调用getContentResolver().query()
或直接查询数据库。
如果以上都不起作用,也许您可以将使用单独的CursorLoaders处理的数据拆分为单独的CursorProviders。