更新一个游标行会在不应该更新时更新其他行

时间:2013-09-12 22:06:04

标签: android android-sqlite android-contentprovider android-cursoradapter

所以我编写了一个自定义游标适配器来处理列表行的自定义布局。 该布局包括ToggleButton,ImageButton和TextView。 TextView数据派生自名为ALARM_TIME的列,并且可以正常加载。

但是ToggleButton会导致问题。它的状态来自一个名为ALARM_ISACTIVE的列,它将为1(对应于'on')或0(对应于'off')。单击ToggleButton应相应地更新数据库中的相应行。

然而,无论出于何种原因,我的实际行为与此完全不同。

单击ToggleButton会触发我单击的行和列表的前两行的OnCheckedChange侦听器,无论我单击哪一行。此外,如果我检查一行,向下滚动,然后向上滚动,那么行的状态就不会持久。

我不确定这里发生了什么,也不知道如何解释或修复它。

有人可以帮我吗?

作为参考,这是我的光标适配器:

public class AlarmCursorAdapter extends SimpleCursorAdapter implements OnCheckedChangeListener {

private Context mContext;
private int mLayout;
private Cursor mCursor;
private int mIdIndex;
private int mAlarmIndex;
private int mIsActiveIndex;
private LayoutInflater mInflater;

public AlarmCursorAdapter(Context context, int layout, Cursor c,
        String[] from, int[] to, int flags) {
    super(context, layout, c, from, to, flags);
    Log.d("alarmAdapter", "calling constructor");
    this.mContext = context;
    this.mLayout = layout;
    this.mCursor = c;
    this.mIdIndex = c.getColumnIndexOrThrow(DailyAlarmTable.ALARM_ID);
    this.mAlarmIndex = c.getColumnIndexOrThrow(DailyAlarmTable.ALARM_TIME);
    this.mIsActiveIndex = c.getColumnIndexOrThrow(DailyAlarmTable.ALARM_ISACTIVE);
    this.mInflater = LayoutInflater.from(mContext);
    Log.d("alarmAdapter", "finishing constructor");
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if(mCursor.moveToPosition(position)) {
        ViewHolder holder;
        final int fPosition = position;
        Log.d("AlarmCursorAdapter", "getView called for position " + fPosition);
        // If the view isn't inflated, we need to create it
        if(convertView == null) {
            Log.d("AlarmAdapter", "creating position " + fPosition);
            convertView = mInflater.inflate(mLayout, null);

            holder = new ViewHolder();

            holder.alarmView = (TextView) convertView.findViewById(R.id.alarmView);
            holder.discardButton = (ImageButton) convertView.findViewById(R.id.alarmDiscard);
            holder.isActiveToggle = (ToggleButton) convertView.findViewById(R.id.alarmToggle);

            convertView.setTag(holder);
        } else { // If the view is already inflated, we need to get it for the holder
            Log.d("AlarmAdapter", "recycling position " + fPosition);
            holder = (ViewHolder) convertView.getTag();
        }

        // Populate the views
        String alarmString = mCursor.getString(mAlarmIndex);
        int isActive = mCursor.getInt(mIsActiveIndex);
        final int id = mCursor.getInt(mIdIndex);
        holder.alarmView.setText(alarmString);
        if(isActive == 1) {
            holder.isActiveToggle.setChecked(true);
        } else {
            holder.isActiveToggle.setChecked(false);
        }

        holder.isActiveToggle.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton button, boolean isChecked) {
                Log.d("ToggleListener", "Toggle for " + fPosition + " triggered");
                if(isChecked) {
                    Toast.makeText(mContext, "row " + fPosition + " is checked", Toast.LENGTH_SHORT).show();
                    // Change the value of ALARM_ISACTIVE in the cursor to 1
                    ContentValues newValues = new ContentValues();
                    newValues.put(DailyAlarmTable.ALARM_ISACTIVE, 1);
                    String selection = "(" + DailyAlarmTable.ALARM_ID + " = " + id + ")";
                    int rowsUpdated = 0;
                    rowsUpdated = mContext.getContentResolver().update(AlarmProvider.CONTENT_URI,
                            newValues, selection, null);

                } else {
                    Toast.makeText(mContext, "row " + fPosition + " is unchecked", Toast.LENGTH_SHORT).show();
                    // Change the value of ALARM_ISACTIVE in the cursor to 0
                    ContentValues newValues = new ContentValues();
                    newValues.put(DailyAlarmTable.ALARM_ISACTIVE, 0);
                    String selection = "(" + DailyAlarmTable.ALARM_ID + " = " + id + ")";
                    int rowsUpdated = 0;
                    rowsUpdated = mContext.getContentResolver().update(AlarmProvider.CONTENT_URI,
                            newValues, selection, null);
                }
            }
        });

    }
    return convertView;
}

static class ViewHolder {
    ToggleButton isActiveToggle;
    TextView alarmView;
    ImageButton discardButton;
}

@Override
public void onCheckedChanged(CompoundButton button, boolean isChecked) {
    // TODO Auto-generated method stub

}
}

这是我的内容提供商提供的update()方法。我是为了彻底而包括这个,因为问题更严重(一旦我点击任何一行,行就会无限更新以响应彼此),直到我发现我不应该调用notifyChange():

@Override
public int update(Uri uri, ContentValues values, String selection,
        String[] selectionArgs) {
    int uriType = sUriMatcher.match(uri);
    SQLiteDatabase db = database.getWritableDatabase();
    int rowsUpdated = 0;
    switch(uriType) {
    case ALARMS:
        rowsUpdated = db.update(DailyAlarmTable.TABLE_ALARM,
                values,
                selection,
                selectionArgs);
        break;
    case ALARM_ID:
        String id = uri.getLastPathSegment();
        if(TextUtils.isEmpty(selection)) {
            rowsUpdated = db.update(DailyAlarmTable.TABLE_ALARM,
                    values,
                    DailyAlarmTable.ALARM_ID + "=" + id,
                    null);
        } else {
            rowsUpdated = db.update(DailyAlarmTable.TABLE_ALARM,
                    values,
                    DailyAlarmTable.ALARM_ID + "=" + id + " and " + selection,
                    selectionArgs);
        }
        break;
    default:
        throw new IllegalArgumentException("Unknown URI: " + uri);
    }
//      getContext().getContentResolver().notifyChange(uri, null);
    return rowsUpdated;
}

1 个答案:

答案 0 :(得分:0)

结果我需要在自定义光标适配器中实现一个布尔数组来存储切换按钮的状态。