Android的ListView控件与SimpleCursorAdapter - 崩溃onResume [英] Android ListView with SimpleCursorAdapter - Crashes onResume

查看:134
本文介绍了Android的ListView控件与SimpleCursorAdapter - 崩溃onResume的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个的ListView AcitivityA 正在使用自定义的填充 SimpleCursorAdapter 名为 RecipeAdapter 。该适配器拥有的SQLite

数据

有位于的ListView ,用于过滤列表视图作为用户搜索的顶部有一个的EditText 视图一个食谱。当用户点击在经过过滤的ListView ActivityB 启动一个项目。

这一切完美的作品。然而,当用户presses的后退按钮恢复 ActivityB ,我碰到下面的错误。

  java.lang.IllegalStateException:
试图重新查询已经关闭的游标android.database.sqlite.SQLiteCursor@418af170

我在尝试解决这个问题:


  • 复制从code中的的onCreate() onResume 方法。

  • 添加 c.requery() onResume()

  • 添加 db.close 的onDestroy()

谁能帮我与我的问题?

下面是我的code:

的onCreate 光标填充的ListView 使用 c.getCursor 键,当用户过滤的ListView 通过的EditText c.getFilterCursor 被使用。

 公共类RecipeActivity扩展SherlockListActivity {私人DBHelper DB = NULL;
私人光标C = NULL;
私人RecipeAdapter适配器= NULL;
ListView控件的listContent;
私人的EditText filterText = NULL;@燮pressWarnings(德precation)
@覆盖
公共无效的onCreate(捆绑savedInstanceState){
    尝试{
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.filter_list);        filterText =(EditText上)findViewById(R.id.search_box);
        filterText.addTextChangedListener(filterTextWatcher);        ListView控件的listContent = getListView();        DB =新DBHelper(本);
        db.createDataBase();
        db.openDataBase();        C = db.getCursor();        适配器=新RecipeAdapter(C);        listContent.setAdapter(适配器);        adapter.setFilterQueryProvider(新FilterQueryProvider(){
            公共光标runQuery(CharSequence的约束){
                //搜索状态,其名称以字母指定。
                C = db.getFilterCursor(约束);
                返回℃;
            }
        });        startManagingCursor(C);
    }赶上(IOException异常五){
        e.printStackTrace();
    }
}
    私人TextWatcher filterTextWatcher =新TextWatcher(){    公共无效afterTextChanged(编辑S){
    }    公共无效beforeTextChanged(CharSequence中,诠释开始,诠释计数,
            INT后){
    }    公共无效之前onTextChanged(CharSequence中,诠释开始,诠释,
            诠释计数){        。adapter.getFilter()过滤器(S);
    }};

RecipeAdapter内部类

 类RecipeAdapter扩展的CursorAdapter {    @燮pressWarnings(德precation)
    公共RecipeAdapter(光标C){
        超(RecipeActivity.this,C);
    }    公共无效bindView(查看排,上下文ARG1,ARG2光标){
        RecipeHolder支架=(RecipeHolder)row.getTag();
        holder.populateFrom(C,DB);    }    公共查看NewView的(上下文为arg0,ARG1光标,ViewGroup中ARG2){
        LayoutInflater吹气= getLayoutInflater();
        查看排= inflater.inflate(R.layout.reciperow,ARG2,FALSE);
        RecipeHolder持有人=新RecipeHolder(行);
        row.setTag(保持器);        返回(行);
    }
静态类RecipeHolder {
    公众的TextView ID = NULL;
    私人TextView的名字= NULL;
    私人TextView的递减= NULL;
    私人TextView的preptime = NULL;
    私人TextView的cooktime = NULL;
    私人TextView的服务= NULL;
    私人TextView的热量= NULL;
    私人TextView的脂肪= NULL;
    私人TextView的最爱= NULL;    RecipeHolder(查看行){
        ID =(TextView中)row.findViewById(R.id.id);
        名称=(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);
        供应=(TextView中)row.findViewById(R.id.serving);
        卡路里=(TextView中)row.findViewById(R.id.calories);
        脂肪=(TextView中)row.findViewById(R.id.fat);
        最爱=(TextView中)row.findViewById(R.id.fav);
    }
    无效populateFrom(光标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.get prepTime(C)+。);
        cooktime.setText(r.getCookTime(C)+分钟);
        serves.setText(r.getServes(C));
        calories.setText(r.getCalories(C));
        fat.setText(r.getFat(C));
        fav.setText(r.getFav(C));

getCursor()和getFilterCursor()从DBHelper类code

 公共光标getCursor(){
    SQLiteQueryBuilder的QueryBuilder =新SQLiteQueryBuilder();
    queryBuilder.setTables(DATABASE_TABLE);    的String [] =列新的String [] {KEY_ROWID,食谱,DESC,prePTIME,
            COOKTIME,服务,热量,脂肪,类别,FAV};    光标myCursor = queryBuilder.query(MYDATABASE,列,NULL,NULL,
            NULL,NULL,食谱+ASC);    返回myCursor;
}
公共光标getFilterCursor(CharSequence的约束){
    SQLiteQueryBuilder的QueryBuilder =新SQLiteQueryBuilder();
    queryBuilder.setTables(DATABASE_TABLE);    的String [] =列新的String [] {KEY_ROWID,食谱,DESC,prePTIME,
            COOKTIME,服务,热量,脂肪,类别,FAV};    如果(约束== NULL || constraint.length()== 0){
        //返回完整列表
        返回queryBuilder.query(MYDATABASE,列,NULL,NULL,NULL,
                空,食谱+ASC);
    }其他{
        字符串值=%+ constraint.toString()+%;        返回myDataBase.query(DATABASE_TABLE,列配方样?,
                新的String [] {}值,NULL,NULL,NULL);
    }
}

FULL logcat的

 致命异常:主要
了java.lang.RuntimeException:无法恢复活动{ttj.android.quorn / ttj.android.quorn.RecipeActivity}:
java.lang.IllegalStateException:尝试重新查询已经关闭的游标android.database.sqlite.SQLiteCursor@41954658
在android.app.ActivityThread.performResumeActivity(ActivityThread.java:2456)
在android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2484)
在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1185)
在android.os.Handler.dispatchMessage(Handler.java:99)
在android.os.Looper.loop(Looper.java:137)
在android.app.ActivityThread.main(ActivityThread.java:4507)
在java.lang.reflect.Method.invokeNative(本机方法)
在java.lang.reflect.Method.invoke(Method.java:511)
在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:790)
在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
在dalvik.system.NativeStart.main(本机方法)
java.lang.IllegalStateException:引起试图重新查询已经关闭游标android.database.sqlite.SQLiteCursor@41954658
在android.app.Activity.performRestart(Activity.java:4508)
在android.app.Activity.performResume(Activity.java:4531)
在android.app.ActivityThread.performResumeActivity(ActivityThread.java:2446)


解决方案

Wha't您正在运行应用程序Android平台的版本?这种方法startManagingCursor是因为蜂窝pcated德$ P $。开发者建议使用与LoaderManager而不是新的CursorLoader类,它也可在通过Android兼容包旧的平台。

其实我得到了蜂窝同样的问题。不过,我没有按照上述说明,因为我没有太多的时间来重写我的code。因此,这里是我的解决方案,我希望它能帮助。但是,如果你有时间,你应该切换到使用CursorLoader和LoaderManager其获得更好的性能。

  @覆盖
保护无效onResume(){
    super.onResume();
    //再次恢复,每次做查询
    光标C = mExpenseDb.queryCategories(mSettings.getCurrentAccount()的getId());
    // mAdapter是SimpleCursorAdapter,其设置光标到新的
    mAdapter.changeCursor(C);
}@覆盖
保护无效的onPause(){
    super.onPause();
    // mAdapter是SimpleCursorAdapter,废止其数据并设置光标到零上的活动暂停
    mAdapter.notifyDataSetInvalidated();    mAdapter.changeCursor(NULL);
}

I have a ListView in AcitivityA that is populated using a custom SimpleCursorAdapter called RecipeAdapter. The adapter holds data from SQLite

There is a EditText view at the top of the ListView, that filters the listview as the user searches for a recipe. When a user clicks on a item in the filtered ListView, ActivityB starts.

This all works perfectly. However when the user presses the backbutton to resume ActivityB, I get the following error.

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

My attempts at fixing the problem:

  • Duplicating code from the onCreate() to the onResume method.
  • Adding c.requery() to onResume() method
  • Adding db.close to onDestroy() method

Can anyone help me with my problem?

Here is my code:

In the onCreate, the cursor populate the ListView using c.getCursor and when the user filters the ListView via the EditText, the c.getFilterCursor is used.

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 inner class

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() and getFilterCursor() code from DBHelper class

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)

解决方案

Wha't the version of Android platform you are running your application? This method startManagingCursor is deprecated since Honeycomb. Developers are suggested to use the new CursorLoader class with LoaderManager instead, which is also available on older platforms through the Android compatibility package.

Actually I got the same problem on Honeycomb. However I didn't follow above instructions as I don't have much time to rewrite my code. So here is my solution, I hope it helps. But if you have time, you should switch to use CursorLoader and LoaderManager which gains much better performance.

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

这篇关于Android的ListView控件与SimpleCursorAdapter - 崩溃onResume的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆