【问题标题】:Android ListView with SimpleCursorAdapter - Crashes onResume带有 SimpleCursorAdapter 的 Android ListView - 崩溃 onResume
【发布时间】:2012-08-10 00:07:28
【问题描述】:

我在AcitivityA 中有一个ListView,它使用名为RecipeAdapter 的自定义SimpleCursorAdapter 填充。适配器保存来自SQLite的数据

EditText 顶部有一个 EditText 视图,用于在用户搜索食谱时过滤列表视图。当用户点击过滤后的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 使用c.getCursor 填充ListView,当用户通过EditText 过滤ListView 时,使用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));

DBHelper 类中的 getCursor() 和 getFilterCursor() 代码

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);
    }
}

完整的 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)

【问题讨论】:

  • 请发布您所有的 LogCat 错误并指出最后一个错误发生的行。
  • @Sam Logcat 现在包含在问题中。
  • 由于你是在 onCreate() 中打开你的数据库,你应该在 onDestroy() 中添加db.close()db.getCursor() 的代码是什么?
  • @Sam 我已将db.close() 添加到onDestroy(),这没什么区别。现在分享getCursor()代码。
  • 使用db.close() 只是一个好习惯。顺便说一句,这是对newView() 和bindView() 的伟大 使用,您不只是盲目地覆盖getView()。但是我无法理解您的 LogCat ...

标签: java android listview cursor simplecursoradapter


【解决方案1】:

您运行应用程序的 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);
}

【讨论】:

  • 今晚回家后我会试一试。我应该修改我的onCreate() 吗?
  • 我收到一个错误android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 70。我的清单有 70 项。我在getCursor() 中有cursor.moveToFirst()DBHelper.class 但发生停止异常。
  • @tiptopjat 对不起,我出差了,所以没有机会回答你的问题。这是我的建议。在 onCreate() 方法中进行 dbHelper 和 cursorAdaptor 初始化,在 onResume() 方法中进行数据库查询和更改游标。关于 CursorIndexOutOfBoundsException,如果你提前调用 cursor.moveToFirst() 应该不会发生。如果可能的话,你能分享你更新的代码吗?谢谢。 -杰
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 2012-08-03
  • 1970-01-01
  • 2011-08-20
  • 1970-01-01
  • 2013-10-26
  • 1970-01-01
相关资源
最近更新 更多