【问题标题】:CursorLoader and Finalizing cursor that has not been deactivated or closed errorCursorLoader 和 Finalizing 未停用或关闭的游标错误
【发布时间】:2012-01-14 05:01:49
【问题描述】:

在我的活动中,我有 2 个 CursorLoader 和 2 个 TextView 以及一个调用 setScreen() 方法的 OnClickListener。单击 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 应该管理光标并在必要时关闭它。

【问题讨论】:

    标签: android android-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. 如果上述方法都不起作用,也许您可​​以将使用单独的 CursorLoader 处理的数据拆分为单独的 CursorProviders。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-22
      • 2012-01-22
      • 1970-01-01
      • 2013-05-27
      相关资源
      最近更新 更多