所以我写了一个自定义光标适配器来处理列表行的自定义布局。布局包括一个 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;
}