行背景因回收而发生变化。 getView()实现不能解决这个问题

时间:2013-05-04 10:24:18

标签: android android-listview android-cursoradapter

我一直在寻找关于堆栈的指南,教程和答案,但我仍然无法想出这个。

我有一个自定义绘制状态。如果我点击ListView中的一行,它会突出显示并在数据库中更新此信息。 (已完成任务(习惯))。一切都很好,直到我开始滚动。我了解到,需要覆盖getView()方法,而getItemViewType()可能会覆盖getViewTypeCount()

如何正确地做到这一点?我目前使用getView()和其他提到的方法的HabitsCursorAdapter代码看起来像这样。

public class HabitsCursorAdapter extends CursorAdapter {

    private LayoutInflater inflater;
    private Context context;

public static final int PERFORMED = 1;
public static final int NOT_PERFORMED = 0;

    public HabitsCursorAdapter(Context context, Cursor c) {
        super(context, c, 0);
        inflater = LayoutInflater.from(context);
        this.context = context;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {

        String habitName = cursor.getString(cursor
                .getColumnIndexOrThrow(SQLiteHabitHelper.COLUMN_NAME));
        TextView habitNameTV = (TextView) view.findViewById(R.id.habit_name);
        habitNameTV.setText(habitName);


        /*******************   OK   ***********************/
        ImageButton editButton = (ImageButton) view.findViewById(R.id.habit_edit_button);
        Integer _id = cursor.getInt(cursor.getColumnIndexOrThrow(SQLiteHabitHelper.COLUMN_ID));
        editButton.setTag(R.id.EDITED_HABIT_ID, _id);
        view.setTag(_id);

        editButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent i = new Intent(HabitsCursorAdapter.this.context,
                        HabitDetailActivity.class);
                i.putExtra("_id", (Integer) v.getTag(R.id.EDITED_HABIT_ID));
                HabitsCursorAdapter.this.context.startActivity(i);
            }
        });

        ImageButton deleteButton = (ImageButton) view
                .findViewById(R.id.habit_history_button); // NEED TO REWRITE TO DELETING BUTTON
        deleteButton.setTag(R.id.EDITED_HABIT_ID, _id);
        deleteButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //itemized due debugging issue
                HabitListActivity hla = ((HabitListActivity) HabitsCursorAdapter.this.context);
                Object o = v.getTag(R.id.EDITED_HABIT_ID);
                Integer i = (Integer) o;
                long l = i.longValue();
                hla.delete(l);
            }
        });
        /*******************   OK   **********************/

        HabitListItemView hv = (HabitListItemView) view;
        hv.setHabitPerformed(
                (1 == cursor.getInt(cursor.getColumnIndexOrThrow(SQLiteHabitHelper.COLUMN_PERFORMED))) ? true : false
                    );
        view.refreshDrawableState();
    }

    @Override
    public View newView(Context context, Cursor c, ViewGroup container) {
        HabitListItemView v = (HabitListItemView) inflater.inflate(
                R.layout.habit_item_layout, container, false);
        bindView(v, context, c);        
        return v;
    }

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public int getItemViewType(int position) {

        Cursor c = (Cursor) getItem(position);

        c.moveToPosition(position);
        int value = c.getInt(c.getColumnIndexOrThrow(SQLiteHabitHelper.COLUMN_PERFORMED));
        if(0 != value){
            return PERFORMED;
        }
        return NOT_PERFORMED;

    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (!mDataValid) {
            throw new IllegalStateException("this should only be called when the cursor is valid");
        }
        if (!mCursor.moveToPosition(position)) {
            throw new IllegalStateException("couldn't move cursor to position " + position);
        }
        View v;
        if (convertView == null) {
            v = newView(mContext, mCursor, parent);
            return v;
        } else {

            mCursor.moveToPosition(position);

            HabitListItemView hv = (HabitListItemView) convertView;
            int convertViewIsPerformed = hv.getHabitPerformed() ? 1 : 0;
            int actualItemPerformed = getItemViewType(position); 

            if(actualItemPerformed == convertViewIsPerformed){              
                v = convertView;
                bindView(v, mContext, mCursor);
                return v;
            }else{
                v = newView(mContext, mCursor, parent);
                return v;
            }                       
        }
    }
}

自定义行视图为:

public class HabitListItemView extends RelativeLayout {

    private static final int[] STATE_HABIT_PERFORMED = { R.attr.state_habit_performed };

    private boolean performed;

    public HabitListItemView(Context context) {
        this(context, null);
    }

    public HabitListItemView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        loadViews();
    }

    public HabitListItemView(Context context, AttributeSet attributeSet,
            int defStyle) {
        super(context, attributeSet, defStyle);

        loadViews();
    }

    private void loadViews() {

        setBackgroundResource(R.drawable.habit_list_item_background);   

    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {

        if (performed) {

            final int[] drawableState = super
                    .onCreateDrawableState(extraSpace + 1);

            mergeDrawableStates(drawableState, STATE_HABIT_PERFORMED);

            return drawableState;
        } else {
            return super.onCreateDrawableState(extraSpace);
        }
    }

    public void setHabitPerformed(boolean performed) {
        this.performed = performed;
        refreshDrawableState();
}

public boolean getHabitPerformed() {
    return performed;
}

}

和ListFragment中的onListItemClick()

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {

        super.onListItemClick(l, v, position, id);

        HabitListItemView hv = (HabitListItemView) v;

        ContentValues cv = new ContentValues();



        String habitId = v.getTag().toString(); 
        SQLiteDatabase db = dh.getWritableDatabase();
        Cursor cPerfomed = db.query(SQLiteHabitHelper.TABLE_HABIT, 
                new String[]{SQLiteHabitHelper.COLUMN_ID, SQLiteHabitHelper.COLUMN_PERFORMED}, 
                "_id = ?", new String[]{habitId}, null, null, null);
        cPerfomed.moveToFirst();

        int performed = cPerfomed.getInt(cPerfomed.getColumnIndexOrThrow(SQLiteHabitHelper.COLUMN_PERFORMED));
        cPerfomed.close();

        cv.put(SQLiteHabitHelper.COLUMN_ID, (Integer) v.getTag());
        cv.put(SQLiteHabitHelper.COLUMN_PERFORMED, (performed == 0) ? 1 : 0);

        db.update(SQLiteHabitHelper.TABLE_HABIT, cv, "_id = ?", new String[]{habitId});
        db.close();
        hv.setHabitPerformed((performed == 0) ? true : false);


    }

有关如何以及何时调用覆盖方法的详细解释可能有助于我解决问题。我认为,newView和bindView只能被getView调用,因此我相信我可以通过我的覆盖getView来控制它。但是getItemViewType和getViewTypeCount是由我没有实现的方法调用的,我不明白为什么以及如何使用结果。也许他们会引起问题。

如果需要更多代码,我会根据要求编辑我的帖子。

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

我的一位朋友通过向我发送此链接来帮助我

Android: CursorAdapter, ListView and CheckBox

我尝试了解决方案,但是,我没有使用复选框,但使用背景颜色。

我必须相应地修改getView()方法:

public View getView(int position, View inView, ViewGroup parent) {
    if (inView == null) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inView = inflater.inflate(R.layout.habit_item_layout, null);
    }

    HabitListItemView hliv = (HabitListItemView) inView;

        mCursor.moveToPosition(position);
    bindView(hliv, mContext, mCursor);
    hliv.setHabitPerformed(habitPerformed.get(position)); //line added

    return inView;
}

并向适配器添加一个数组,我存储的地方,如果它应该有一个背景为绿色。

public ArrayList<Boolean> habitPerformed = new ArrayList<Boolean>();

在带有listItemClick()方法列表的片段中,我添加了相应修改数组的代码。

    if (hv.getHabitPerformed()) {
        adapter.habitPerformed.set(position, true);
    } else if (!hv.getHabitPerformed()) {
        adapter.habitPerformed.set(position, false);
    }

这解决了我的问题。