当使用CursorAdapter的回调时,调用initLoader()只能工作一次

时间:2015-01-12 02:37:18

标签: java android callback android-cursoradapter android-cursorloader

在我的活动内部,我有一个代表医生的列表视图。每行都有医生的名字和一个复选框。我已经实施了一个回调界面,以便在选择医生时,所有其他医生都会从列表视图中删除,只剩下选定的医生。

它似乎有效,因为一旦我选择了医生,所有其他人都会被移除。当我取消检查医生时,每个人都被加回。但是,如果我现在选择一个不同的医生,那么原来的医生会停留,而其他所有人都会被移除。

为了更好地解释这个问题,让我们说当我开始活动时,我在列表视图中有两位医生,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,但这似乎没有什么区别。

1 个答案:

答案 0 :(得分:5)

根据initLoader() documentation

  

确保加载程序已初始化并处于活动状态。如果加载器尚不存在,则创建一个加载器(如果活动/片段当前已启动),则启动加载器。 否则将重新使用上次创建的加载程序。

     

在任何一种情况下,给定的回调都与加载器相关联,并在加载器状态发生变化时被调用。 如果在调用点处调用者处于启动状态,并且请求的加载器已经存在并且已经生成了它的数据,那么将立即调用回调onLoadFinished(Loader,D)(在此函数内),所以你必须为此做好准备。

initLoader()仅初始化某个加载程序ID一次,重新使用此后的数据。如果你想抛弃并重新创建一个新的加载器(即使用新的CursorLoader),请在其位置使用restartLoader()(注意:restartLoader()将使加载器初始化就像第一次initLoader(),所以第一次运行时不需要任何特殊逻辑。