我有一个活动,显示医生的列表视图供用户选择。每个listview项目都包含一个复选框和一个医生的名字。我的最终目标是,当用户检查医生时,所有其他人都被移除,只剩下选定的医生。
在适配器类中,我有以下代码片段:
viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
swapCursor(cursor);
}
}
});
我有代码存储前一个光标,以便在未选中医生时可以恢复,但我已删除它以简化此问题。目前,当我选中复选框时,没有任何反应。我尝试添加notifyDataSetChanged()
但是适配器没有注册观察者,所以没有区别。如何让活动知道项目已被选中?
从documentation我知道我应该注册一个DataSetObserver
,但我不知道应该注册哪个对象以及如何注册。
修改
以下是我的Adapter类的一些内容:
public MyAdapter(Context context, Cursor cursor, int flags){
super(context, cursor, flags);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
View view = LayoutInflater.from(context).inflate(R.layout.adapter_layout, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
return view;
}
@Override
public void bindView(View view, final Context context, final Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
String firstName = cursor.getString(cursor.getColumnIndex(DoctorEntry.COLUMN_FIRSTNAME));
String lastName = cursor.getString(cursor.getColumnIndex(DoctorEntry.COLUMN_LASTNAME));
String suffix = cursor.getString(cursor.getColumnIndex(DoctorEntry.COLUMN_SUFFIX));
viewHolder.nameView.setText(firstName + " " + lastName + ", " + suffix);
// Should I add something here?
viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
}
});
}
public static class ViewHolder{
public final CheckBox checkBox;
public final TextView nameView;
public ViewHolder(View view){
checkBox = (CheckBox) view.findViewById(R.id.chooseDoctorCheckBox);
nameView = (TextView) view.findViewById(R.id.chooseDoctorLabel);
}
}
适配器用于实现CursorLoader的活动,以将数据加载到listview中。在活动中,我可以致电doctorAdapter.swapCursor(someCursorIWant);
,但我无法引用所选医生。我试过的东西:
// Set currentDoctor (a property of the adapter class) if a new one is checked.
// Again, other checks removed for simplicity.
viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
currentDoctor = cursor;
notifyDataSetChanged();
}
}
});
然后在活动中:
// Set observers
mDoctorAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
Cursor c = mDoctorAdapter.getCheckedDoctor();
if(c != null)
mDoctorAdapter.swapCursor(c);
}
});
但它没有做我想要的。
答案 0 :(得分:1)
我已经解决了这个问题。我所做的是调整bindView()
方法以在选择医生时存储医生的身份:
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
final long id = cursor.getLong(cursor.getColumnIndex(DoctorEntry._ID));
String firstName = cursor.getString(cursor.getColumnIndex(DoctorEntry.COLUMN_FIRSTNAME));
String lastName = cursor.getString(cursor.getColumnIndex(DoctorEntry.COLUMN_LASTNAME));
String suffix = cursor.getString(cursor.getColumnIndex(DoctorEntry.COLUMN_SUFFIX));
viewHolder.nameView.setText(firstName + " " + lastName + ", " + suffix);
viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
selectedDoctorId = id;
} else{
selectedDoctorId = 0;
}
notifyDataSetChanged();
}
});
}
然后,我在活动中注册了一个新的观察者,并在onChanged()
方法中提取了id并使用新的Uri来查询该医生:
// Add observer for doctor
mDoctorAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
if(!systemEntered && mDoctorAdapter.getSelectedDoctorId() != 0){
Cursor c = getContentResolver().query(
DoctorEntry.buildDoctorUri(mDoctorAdapter.getSelectedDoctorId()),
DOCTOR_COLUMNS,
null,
null,
null
);
systemEntered = true;
mDoctorAdapter.swapCursor(c);
systemEntered = false;
}
}
});
我不得不使用一个名为systemEntered
的布尔标志来防止无限循环。没有它,调用swapCursor()
再次关闭onChanged()
,然后我重新查询,依此类推。现在,当我检查特定医生的复选框时,所有其他人都将从列表中删除。感谢所有花时间研究这个问题的人。
修改强>
根据评论中的建议,我已将此更改为使用回调。在我的适配器类中,我包含以下接口和方法:
private DoctorAdapterCallbacks mCallbacks;
viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked && mCallbacks != null){
mCallbacks.onDoctorChecked(id);
}
}
});
public void onRegisterCallbacks(Activity activity){
mCallbacks = (DoctorAdapterCallbacks) activity;
}
public static interface DoctorAdapterCallbacks{
void onDoctorChecked(long id);
}
在我的活动(实现界面)中,我添加了以下代码:
// Set callbacks (This is in the onCreate method)
mDoctorAdapter.onRegisterCallbacks(this);
@Override
public void onDoctorChecked(long id) {
Bundle args = new Bundle();
args.putLong(SELECTED_DOCTOR_ID, id);
getSupportLoaderManager().initLoader(SELECTED_DOCTOR_LOADER, args, this);
}
我已经创建了另一个CursorLoader,它只能处理一个医生,而且该加载器将替换前一个(所有医生)。再次感谢所有的帮助和建议。
答案 1 :(得分:-1)
您需要做的是从光标中删除选中的项目,但不能直接执行此操作,因此您需要ContentResolver#delete()
来电或SQL
编辑:
您无法仅从光标中删除。您需要重新查询筛选结果,以便在更改选中状态后,还可以更改标记
答案 2 :(得分:-1)
您可以通过两种方式实现它:
1)使用FilterQueryProvider
您使用查询值设置filterQueryProvider
,如果运行它将选择指定的医生。选中医生后,您将filterQueryProvider
设置为适配器constraint value
,例如等于doctor id
。在runQuery
的{{1}}中,您必须返回一个光标,选择具有filterQueryProvider
的医生。然后每次检查医生时,您只需致电constraint id
你还应该覆盖adapter.getFilter().filter(doctoreId)
,因此它不会关闭前一个光标(由加载器返回的光标),因为关闭光标是加载器的责任。
因此,在您的情况下检查光标大小,如果它等于一个关闭它,但如果不是,请不要关闭它。
2)向您的内容提供商添加一个新的uri,用于通过他的id返回医生。然后,当用户检查新医生时,你会调用一个带有加载程序ID的新initLoader和所需的信息包来选择医生。