0

と呼ばれるカスタムを使用して入力されたListViewinがあります。アダプターはからのデータを保持しますAcitivityASimpleCursorAdapterRecipeAdapterSQLite

EditTextの上部にビューがありListView、ユーザーがレシピを検索するときにリストビューをフィルタリングします。ユーザーがフィルター処理されたアイテムをクリックするとListViewActivityBが開始されます。

これはすべて完璧に機能します。ただし、ユーザーが戻るボタンを押して再開するActivityBと、次のエラーが発生します。

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@418ae5d8

この問題を修正するために、onResume()fromを変更しました。

...
c = db.getCursor(); 
adapter.changeCursor(c);

....
Cursor cursor = db.getCursor(); 
adapter.changeCursor(cursor);

次に、次の例外が発生します。getId()Logcatでは、のメソッドで問題が発生しDBHelperます。この方法で追加c.moveToFirst()しましたが、それでも問題は解決しません。

FATAL EXCEPTION: main
android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 70
at android.database.AbstractCursor.checkPosition(AbstractCursor.java:400)
at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
at ttj.android.quorn.DBHelper.getId(DBHelper.java:224)
at ttj.android.quorn.RecipeActivity$RecipeHolder.populateFrom(RecipeActivity.java:650)
at ttj.android.quorn.RecipeActivity$RecipeAdapter.bindView(RecipeActivity.java:572)
at android.support.v4.widget.CursorAdapter.getView(CursorAdapter.java:256)
at android.widget.AbsListView.obtainView(AbsListView.java:2214)
at android.widget.ListView.makeAndAddView(ListView.java:1774)
at android.widget.ListView.fillDown(ListView.java:672)
at android.widget.ListView.fillFromTop(ListView.java:732)
at android.widget.ListView.layoutChildren(ListView.java:1611)
at android.widget.AbsListView.onLayout(AbsListView.java:2044)
at android.view.View.layout(View.java:11418)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
at android.view.View.layout(View.java:11418)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
at android.view.View.layout(View.java:11418)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
at android.view.View.layout(View.java:11418)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
at android.view.View.layout(View.java:11418)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1628)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2585)
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)

誰かが私の問題を手伝ってくれますか?

これが私のコードです:

onCreate、を使用してデータをcursor入力し、ユーザーが経由をフィルタリングすると、が使用されます。ListViewc.getCursorListViewEditTextc.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();
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    filterText.removeTextChangedListener(filterTextWatcher);
    db.close();
}


@SuppressWarnings("deprecation")
@Override
protected void onResume() {
    super.onResume();

    Cursor cursor = db.getCursor(); 
    adapter.changeCursor(cursor);

}


@Override
protected void onPause() {
    super.onPause();

    adapter.notifyDataSetInvalidated();
    adapter.changeCursor(null);

}




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

public String getId(Cursor c) {
               c.moveToFirst();
    return (c.getString(0));
}

public String getRecipe(Cursor c) {
    return (c.getString(1));
}

public String getDesc(Cursor c) {
    return (c.getString(2));
}

public String getPrepTime(Cursor c) {
    return (c.getString(3));
}

public String getCookTime(Cursor c) {
    return (c.getString(4));
}

public String getServes(Cursor c) {
    return (c.getString(5));
}

public String getCalories(Cursor c) {
    return (c.getString(6));
}

public String getFat(Cursor c) {
    return (c.getString(7));
}

public String getCategory(Cursor c) {
    return (c.getString(8));
}

public String getFav(Cursor c) {
    return (c.getString(9));
}
4

2 に答える 2

1
@SuppressWarnings("deprecation")

悪い。それを隠すのではなく、非推奨を取り除く必要があります:)

startManagingCursor(c);

そうしないでください。これにより、すでに閉じられているカーソルで再クエリが発生した可能性があります。その行を削除するだけです。

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

ここを上書きしないでくださいc。まさにreturn db.getFilterCursor(constraint);これがすべきことです。プラスの効果をもたらす可能性のあるその他のもの

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

public RecipeAdapter(Cursor c) {
    // no requeries and no observer required if you change the cursor yourself
    super(RecipeActivity.this, c, 0)
}

次の:

adapter.notifyDataSetInvalidated();
adapter.changeCursor(null);

// change to
adapter.changeCursor(null);
adapter.notifyDataSetChanged(); // maybe without this

私が理解している限り、ドキュメントnotifyDataSetInvalidated()は、データが後で有効にならないことを意味し (「このアダプターが呼び出されると、もはや有効ではなく、それ以上のデータセットの変更を報告するべきではありません。」)、新しいアダプターインスタンスを作成する必要があります。よくわかりません。するだけでnotifyDataSetChanged()うまくいきます。adapter.changeCursor()変更通知を行うことで、すでに暗黙のうちに変更通知が行われる場合さえあるかもしれません。

PS:c.MoveToFirst()必須ではありません。はCursorAdapter、カーソルを必要な位置に移動します。

于 2012-08-10T22:08:03.800 に答える
0

You renamed your variable, as indicated here

....
Cursor cursor = db.getCursor(); 
adapter.changeCursor(cursor);

correct? But right after that you specify that you tried

c.moveToFirst()

So maybe you should set

c = cursor;

So that the rest of your code works?

于 2012-08-10T21:20:17.747 に答える