Android - 为什么 CursorAdaptor 上的切换按钮会在更改后立即重置按钮
Android - Why would Switch button on CursorAdaptor reset button immediately after a change
我正在尝试基于 Switch 更新数据库 table 中的布尔值。 ListView 包含一个语言列表,每个语言都有一个 "Install" 切换按钮。我的 CursorAdapter 正在显示列表和开关。我为每个 Switch 设置了 OnCheckedChangeListeners。当我 select 其中一个开关时,它短暂地显示它已打开,但立即恢复为 "off." 在我的日志记录中,我看到该值设置为 "true" 并且这被发送到 DatabaseProvider 以更新数据库。但紧接着,我看到另一个日志输出,该值为 false,然后在另一个更新中发送到 DatabaseProvider。
游标适配器:
public static class ViewHolder {
public final TextView nameView;
public final Switch installSwitch;
public ViewHolder(View view) {
nameView = (TextView) view.findViewById(R.id.language_textview);
installSwitch = (Switch) view.findViewById(R.id.installed_switch);
}
}
public LanguageAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(R.layout.list_item_language, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
return view;
}
@Override
public void bindView(View view, Context context, final Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
long languageId = cursor.getLong(0);
String word = cursor.getString(1);
boolean langInstalled = Boolean.parseBoolean(cursor.getString(2));
viewHolder.nameView.setText(word);
viewHolder.installSwitch.setChecked(langInstalled);
viewHolder.installSwitch.setTag(languageId);
viewHolder.installSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
long languageId = (long) buttonView.getTag();
ContentValues cv = new ContentValues();
cv.put(TranslationContract.LanguageEntry.COLUMN_INSTALLED, isChecked);
Log.d(LOG_TAG, "onChecked, langID: " + languageId + " isChecked: " + isChecked);
buttonView.getContext().getContentResolver().update(TranslationContract.LanguageEntry.CONTENT_URI, cv, TranslationContract.LanguageEntry._ID+"=?", new String[] {String.valueOf(languageId)});
}
});
}
数据库提供者:
public int update(
Uri uri, ContentValues values, String selection, String[] selectionArgs) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
int rowsUpdated;
switch (match) {
case LANGUAGES:
rowsUpdated = db.update(LanguageEntry.TABLE_NAME, values, selection,
selectionArgs);
Log.d(LOG_TAG, "Updating languages: " + values.toString());
break;
}
日志:
07-13 21:39:32.785 LanguageAdapter﹕ onChecked, langID: 2 isChecked: true
07-13 21:39:32.800 DatabaseProvider﹕ Updating languages: installed=true
07-13 21:39:32.813 LanguageAdapter﹕ onChecked, langID: 2 isChecked: false
07-13 21:39:32.825 DatabaseProvider﹕ Updating languages: installed=false
经过深入挖掘,我发现了两个问题:
首先,onCheckChanged 似乎总是被调用两次,这可能是一个 android 错误?请参阅以下帖子:
onCheckedChanged fired multiple times, Listview with checkbox 和
CheckBox changes value twice
改为使用 onClickListener。
这里的第二个问题是数据库游标和 java 代码之间的布尔值处理不正确。 SQLite 没有本机 BOOLEAN 类型,因此值以整数 0 或 1 的形式存储和返回。需要对它们进行评估,然后将其转换为 java 布尔值。
更正后的代码为:
@Override
public void bindView(View view, Context context, final Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
long languageId = cursor.getLong(0);
String word = cursor.getString(1);
boolean langInstalled = cursor.getInt(2)>0; //convert DB 1 or 0 to java boolean
viewHolder.nameView.setText(word);
viewHolder.installSwitch.setChecked(langInstalled);
viewHolder.installSwitch.setTag(languageId);
viewHolder.installSwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CompoundButton button = (CompoundButton) v;
long languageId = (long) button.getTag();
boolean isChecked = button.isChecked();
int dbBoolean = 0;
if (button.isChecked()) {
dbBoolean = 1;
}
ContentValues cv = new ContentValues();
cv.put(TranslationContract.LanguageEntry.COLUMN_INSTALLED, dbBoolean);
button.getContext().getContentResolver().update(TranslationContract.LanguageEntry.CONTENT_URI, cv, TranslationContract.LanguageEntry._ID + "=?", new String[]{String.valueOf(languageId)});
notifyDataSetChanged();
}
});
}
我正在尝试基于 Switch 更新数据库 table 中的布尔值。 ListView 包含一个语言列表,每个语言都有一个 "Install" 切换按钮。我的 CursorAdapter 正在显示列表和开关。我为每个 Switch 设置了 OnCheckedChangeListeners。当我 select 其中一个开关时,它短暂地显示它已打开,但立即恢复为 "off." 在我的日志记录中,我看到该值设置为 "true" 并且这被发送到 DatabaseProvider 以更新数据库。但紧接着,我看到另一个日志输出,该值为 false,然后在另一个更新中发送到 DatabaseProvider。
游标适配器:
public static class ViewHolder {
public final TextView nameView;
public final Switch installSwitch;
public ViewHolder(View view) {
nameView = (TextView) view.findViewById(R.id.language_textview);
installSwitch = (Switch) view.findViewById(R.id.installed_switch);
}
}
public LanguageAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(R.layout.list_item_language, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
return view;
}
@Override
public void bindView(View view, Context context, final Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
long languageId = cursor.getLong(0);
String word = cursor.getString(1);
boolean langInstalled = Boolean.parseBoolean(cursor.getString(2));
viewHolder.nameView.setText(word);
viewHolder.installSwitch.setChecked(langInstalled);
viewHolder.installSwitch.setTag(languageId);
viewHolder.installSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
long languageId = (long) buttonView.getTag();
ContentValues cv = new ContentValues();
cv.put(TranslationContract.LanguageEntry.COLUMN_INSTALLED, isChecked);
Log.d(LOG_TAG, "onChecked, langID: " + languageId + " isChecked: " + isChecked);
buttonView.getContext().getContentResolver().update(TranslationContract.LanguageEntry.CONTENT_URI, cv, TranslationContract.LanguageEntry._ID+"=?", new String[] {String.valueOf(languageId)});
}
});
}
数据库提供者:
public int update(
Uri uri, ContentValues values, String selection, String[] selectionArgs) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
int rowsUpdated;
switch (match) {
case LANGUAGES:
rowsUpdated = db.update(LanguageEntry.TABLE_NAME, values, selection,
selectionArgs);
Log.d(LOG_TAG, "Updating languages: " + values.toString());
break;
}
日志:
07-13 21:39:32.785 LanguageAdapter﹕ onChecked, langID: 2 isChecked: true
07-13 21:39:32.800 DatabaseProvider﹕ Updating languages: installed=true
07-13 21:39:32.813 LanguageAdapter﹕ onChecked, langID: 2 isChecked: false
07-13 21:39:32.825 DatabaseProvider﹕ Updating languages: installed=false
经过深入挖掘,我发现了两个问题:
首先,onCheckChanged 似乎总是被调用两次,这可能是一个 android 错误?请参阅以下帖子: onCheckedChanged fired multiple times, Listview with checkbox 和 CheckBox changes value twice
改为使用 onClickListener。
这里的第二个问题是数据库游标和 java 代码之间的布尔值处理不正确。 SQLite 没有本机 BOOLEAN 类型,因此值以整数 0 或 1 的形式存储和返回。需要对它们进行评估,然后将其转换为 java 布尔值。
更正后的代码为:
@Override
public void bindView(View view, Context context, final Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
long languageId = cursor.getLong(0);
String word = cursor.getString(1);
boolean langInstalled = cursor.getInt(2)>0; //convert DB 1 or 0 to java boolean
viewHolder.nameView.setText(word);
viewHolder.installSwitch.setChecked(langInstalled);
viewHolder.installSwitch.setTag(languageId);
viewHolder.installSwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CompoundButton button = (CompoundButton) v;
long languageId = (long) button.getTag();
boolean isChecked = button.isChecked();
int dbBoolean = 0;
if (button.isChecked()) {
dbBoolean = 1;
}
ContentValues cv = new ContentValues();
cv.put(TranslationContract.LanguageEntry.COLUMN_INSTALLED, dbBoolean);
button.getContext().getContentResolver().update(TranslationContract.LanguageEntry.CONTENT_URI, cv, TranslationContract.LanguageEntry._ID + "=?", new String[]{String.valueOf(languageId)});
notifyDataSetChanged();
}
});
}