Android ListView с SimpleCursorAdapter - Сбои в резюме

1

У меня есть ListView в AcitivityA, который заполняется с помощью пользовательского SimpleCursorAdapter, называемого RecipeAdapter. Адаптер содержит данные из SQLite

В верхней части ListView отображается представление EditText, которое фильтрует listview, когда пользователь выполняет поиск рецепта. Когда пользователь нажимает на элемент в отфильтрованном ListView, начинается ActivityB.

Все работает отлично. Однако, когда пользователь нажимает кнопку, чтобы возобновить ActivityB, я получаю следующую ошибку.

java.lang.IllegalStateException:
trying to requery an already closed cursor  android.database.sqlite.SQLiteCursor@418af170

Мои попытки устранить проблему:

  • Дублирование кода из метода onCreate() в onResume.
  • Добавление метода c.requery() в onResume()
  • Добавление метода db.close в onDestroy()

Может ли кто-нибудь помочь мне с моей проблемой?

Вот мой код:

В onCreate, cursor заполнить ListView, используя c.getCursor, и когда пользователь фильтрует ListView через EditText, используется c.getFilterCursor.

public class RecipeActivity extends SherlockListActivity {

private DBHelper db = null;
private Cursor c = null;
private RecipeAdapter adapter = null;
ListView listContent;   
private EditText filterText = null;

@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
    try {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.filter_list);

        filterText = (EditText) findViewById(R.id.search_box);
        filterText.addTextChangedListener(filterTextWatcher);

        ListView listContent = getListView();

        db = new DBHelper(this);
        db.createDataBase();
        db.openDataBase();

        c = db.getCursor();         

        adapter = new RecipeAdapter(c);

        listContent.setAdapter(adapter);

        adapter.setFilterQueryProvider(new FilterQueryProvider() {
            public Cursor runQuery(CharSequence constraint) {
                // Search for states whose names begin with the specified letters.
                c = db.getFilterCursor(constraint);
                return c;
            }
        });

        startManagingCursor(c);


    } catch (IOException e) {
        e.printStackTrace();
    }
}




    private TextWatcher filterTextWatcher = new TextWatcher() {

    public void afterTextChanged(Editable s) {
    }

    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
    }

    public void onTextChanged(CharSequence s, int start, int before,
            int count) {

        adapter.getFilter().filter(s);


    }

};

Внутренний класс RecipeAdapter

class RecipeAdapter extends CursorAdapter {

    @SuppressWarnings("deprecation")
    public RecipeAdapter(Cursor c) {
        super(RecipeActivity.this, c);
    }

    public void bindView(View row, Context arg1, Cursor arg2) {
        RecipeHolder holder = (RecipeHolder) row.getTag();
        holder.populateFrom(c, db);

    }

    public View newView(Context arg0, Cursor arg1, ViewGroup arg2) {
        LayoutInflater inflater = getLayoutInflater();
        View row = inflater.inflate(R.layout.reciperow, arg2, false);
        RecipeHolder holder = new RecipeHolder(row);
        row.setTag(holder);

        return (row);
    }


static class RecipeHolder {
    public TextView id = null;
    private TextView name = null;
    private TextView desc = null;
    private TextView preptime = null;
    private TextView cooktime = null;
    private TextView serves = null;
    private TextView calories = null;
    private TextView fat = null;
    private TextView fav = null;

    RecipeHolder(View row) {
        id = (TextView) row.findViewById(R.id.id);
        name = (TextView) row.findViewById(R.id.recipe);
        desc = (TextView) row.findViewById(R.id.desc);
        preptime = (TextView) row.findViewById(R.id.preptime);
        cooktime = (TextView) row.findViewById(R.id.cooktime);
        serves = (TextView) row.findViewById(R.id.serving);
        calories = (TextView) row.findViewById(R.id.calories);
        fat = (TextView) row.findViewById(R.id.fat);
        fav = (TextView) row.findViewById(R.id.fav);
    }


    void populateFrom(Cursor c, DBHelper r) {
        id.setText(r.getId(c));
        name.setText(r.getRecipe(c));
        name.setTextColor(Color.parseColor("#CCf27c22"));
        desc.setText(r.getDesc(c));
        preptime.setText(r.getPrepTime(c) + ". ");
        cooktime.setText(r.getCookTime(c) + " mins");
        serves.setText(r.getServes(c));
        calories.setText(r.getCalories(c));
        fat.setText(r.getFat(c));
        fav.setText(r.getFav(c));

getCursor() и getFilterCursor() из класса DBHelper

public Cursor getCursor() {
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
    queryBuilder.setTables(DATABASE_TABLE);

    String[] columns = new String[] { KEY_ROWID, RECIPE, DESC, PREPTIME,
            COOKTIME, SERVES, CALORIES, FAT, CATEGORY, FAV };

    Cursor myCursor = queryBuilder.query(myDataBase, columns, null, null,
            null, null, RECIPE + " ASC");

    return myCursor;
}




public Cursor getFilterCursor(CharSequence constraint) {
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
    queryBuilder.setTables(DATABASE_TABLE);

    String[] columns = new String[] { KEY_ROWID, RECIPE, DESC, PREPTIME,
            COOKTIME, SERVES, CALORIES, FAT, CATEGORY, FAV };

    if (constraint == null || constraint.length() == 0) {
        // Return the full list
        return queryBuilder.query(myDataBase, columns, null, null, null,
                null, RECIPE + " ASC");
    } else {
        String value = "%" + constraint.toString() + "%";

        return myDataBase.query(DATABASE_TABLE, columns, "RECIPE like ? ",
                new String[] { value }, null, null, null);
    }
}

FULL LOGCAT

FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to resume activity {ttj.android.quorn/ttj.android.quorn.RecipeActivity}: 
java.lang.IllegalStateException: trying to requery an already closed cursor android.database.sqlite.SQLiteCursor@41954658
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2456)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2484)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1185)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4507)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: trying to requery an already closed cursor android.database.sqlite.SQLiteCursor@41954658
at android.app.Activity.performRestart(Activity.java:4508)
at android.app.Activity.performResume(Activity.java:4531)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2446)
  • 0
    Пожалуйста, опубликуйте все ошибки LogCat и укажите строку, где произошла последняя ошибка.
  • 0
    @Sam Logcat включен в вопрос сейчас.
Показать ещё 3 комментария
Теги:
listview
cursor
simplecursoradapter

1 ответ

2
Лучший ответ

Какую версию платформы Android вы используете для своего приложения? Этот метод startManagingCursor устарел, поскольку Honeycomb. Разработчикам предлагается вместо этого использовать новый класс CursorLoader с LoaderManager, который также доступен на старых платформах через пакет совместимости с Android.

На самом деле у меня такая же проблема для Honeycomb. Однако я не следовал инструкциям, так как у меня не так много времени, чтобы переписать мой код. Итак, вот мое решение, я надеюсь, что это поможет. Но если у вас есть время, вы должны переключиться на использование CursorLoader и LoaderManager, которые получают гораздо лучшую производительность.

@Override
protected void onResume() {
    super.onResume();
    //do the query again every time on resume
    Cursor c = mExpenseDb.queryCategories(mSettings.getCurrentAccount().getId());
    //mAdapter is a SimpleCursorAdapter, set its cursor to the new one 
    mAdapter.changeCursor(c);
}

@Override
protected void onPause() {
    super.onPause();
    //mAdapter is a SimpleCursorAdapter, invalidate its data and set it cursor to null on Activity pause
    mAdapter.notifyDataSetInvalidated();

    mAdapter.changeCursor(null);
}
  • 0
    Я сделаю это, когда вернусь домой сегодня вечером. Должен ли я onCreate() изменить мой onCreate() ?
  • 0
    Я получаю сообщение об ошибке android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 70 . В моем списке 70 наименований. У меня есть cursor.moveToFirst() в моем getCursor() в DBHelper.class но происходит исключение остановки.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню