CursorLoader и Завершение курсора, который не был деактивирован или закрыт ошибка - PullRequest
0 голосов
/ 29 ноября 2011

В моей деятельности у меня есть 2 CursorLoader и 2 TextView с OnClickListener, который вызывает метод 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 должен управлять курсором и закрывать его при необходимости.

1 Ответ

1 голос
/ 14 января 2012

Не уверен, если что-либо из этого связано с вашей проблемой, но здесь идет речь:

  1. Я бы не стал звонить getSupportLoaderManager().initLoader() до того, как вы создадите свои адаптеры.Возможно, это работает, но если onLoadFinished() вызывается до создания адаптеров, мне кажется, что это может вызвать проблемы.

  2. Почему вы звоните getContentResolver().notifyChange() в своем setScreen() метод?Насколько я понимаю, 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.

...