在我的活动内部,我有一个代表医生的列表视图。每行都有医生的名字和一个复选框。我已经实施了一个回调界面,以便在选择医生时,所有其他医生都会从列表视图中删除,只剩下选定的医生。
它似乎有效,因为一旦我选择了医生,所有其他人都会被移除。当我取消检查医生时,每个人都被加回。但是,如果我现在选择一个不同的医生,那么原来的医生会停留,而其他所有人都会被移除。
为了更好地解释这个问题,让我们说当我开始活动时,我在列表视图中有两位医生,Joel和Sam。我想我想选择Joel,所以我这样做,而且Sam从列表中删除了。然后,我意识到我错了,所以我取消选择乔尔,我现在看到列表中的乔尔和萨姆。最后,我选择了Sam。但是,Sam被从列表中删除,只有Joel再次出现。
以下是适配器类的一些代码片段:
@Override
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));
viewHolder.nameView.setText(firstName);
viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(mCallbacks != null){
if(isChecked){
mCallbacks.onDoctorChecked(id);
} else{
mCallbacks.onDoctorUnchecked();
}
}
}
});
}
public void onRegisterCallbacks(DoctorAdapterCallbacks activity){
mCallbacks = activity;
}
public static interface DoctorAdapterCallbacks{
void onDoctorChecked(long id);
void onDoctorUnchecked();
}
在我的活动中,我有以下实现:
@Override
public void onDoctorChecked(long id) {
Bundle args = new Bundle();
args.putLong(SELECTED_DOCTOR_ID, id);
getSupportLoaderManager().initLoader(SELECTED_DOCTOR_LOADER, args, this);
}
@Override
public void onDoctorUnchecked() {
getSupportLoaderManager().initLoader(DOCTOR_LOADER, null, this);
}
DOCTOR_LOADER
是一个CursorLoader,代表表中的所有医生。 SELECTED_DOCTOR_ID
是仅适用于单个医生的CursorLoader。
如果我不得不猜测,我的问题在于bindView
方法,因为我将id变量声明为final。我这样做的原因是因为否则我收到编译器错误:
错误:从内部类中访问局部变量id;需要被宣布为最终
声明变量final
会造成麻烦吗?有没有人看到问题?
修改
我已在适配器的onCheckedChangedListener
和活动的onDoctorSelected
中添加了日志语句。使用上面的相同示例,我看到以下输出:
> onCheckedChanged : Selecting doctor id: 1 // Joel
> onDoctorSelected : Selecting doctor id: 1 // Joel
> onCheckedChanged : Selecting doctor id: 2 // Sam
> onDoctorSelected : Selecting doctor id: 2 // Sam
所以,它似乎确实看到我选择了Sam,id为2,并且它将id 2传递给initLoader()方法,但是只有Joel(doctor id 1)显示在listview中,因为我选择了他第一个。
编辑2
根据请求,这里是CursorLoader方法的片段:
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
switch(i){
case DOCTOR_LOADER:
return new CursorLoader(
this,
DoctorEntry.CONTENT_URI,
DOCTOR_COLUMNS,
null,
null,
null
);
case SELECTED_DOCTOR_LOADER:
long _id = bundle.getLong(SELECTED_DOCTOR_ID);
return new CursorLoader(
this,
DoctorEntry.buildDoctorUri(_id),
DOCTOR_COLUMNS,
DoctorEntry._ID + " = '" + _id + "'",
null,
null
);
default:
throw new UnsupportedOperationException("Unknown loader id: " + i);
}
}
@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
switch(cursorLoader.getId()){
case DOCTOR_LOADER:
case SELECTED_DOCTOR_LOADER:
mDoctorAdapter.swapCursor(cursor);
break;
default:
throw new UnsupportedOperationException("Unknown loader id: " + cursorLoader.getId());
}
}
编辑3
我在onCreateLoader
中添加了另一个日志语句,以查看正在创建加载器的ID。然后,我看到了这个输出:
> onCheckedChanged : Selecting doctor id: 2
> onDoctorSelected : Selecting doctor id: 2
> onCreateLoader : Using id: 2
> // Unchecked, and now check doctor one
> onCheckedChanged : Selecting doctor id: 1
> onDoctorSelected : Selecting doctor id: 1
这不是拼写错误。第二次选择医生时,似乎onCreateLoader是而不是。我试过在destroyLoader()
内调用onDoctorChecked
,但这似乎没有什么区别。
答案 0 :(得分:5)
确保加载程序已初始化并处于活动状态。如果加载器尚不存在,则创建一个加载器(如果活动/片段当前已启动),则启动加载器。 否则将重新使用上次创建的加载程序。
在任何一种情况下,给定的回调都与加载器相关联,并在加载器状态发生变化时被调用。 如果在调用点处调用者处于启动状态,并且请求的加载器已经存在并且已经生成了它的数据,那么将立即调用回调onLoadFinished(Loader,D)(在此函数内),所以你必须为此做好准备。
initLoader()
仅初始化某个加载程序ID一次,重新使用此后的数据。如果你想抛弃并重新创建一个新的加载器(即使用新的CursorLoader
),请在其位置使用restartLoader()(注意:restartLoader()
将使加载器初始化就像第一次initLoader()
,所以第一次运行时不需要任何特殊逻辑。