0

そこで、リスト行のカスタム レイアウトを処理するカスタム カーソル アダプターを作成しました。レイアウトには、ToggleButton、ImageButton、および TextView が含まれます。TextView データは ALARM_TIME という列から派生し、正常にロードされます。

ただし、ToggleButton が問題を引き起こしています。その状態は ALARM_ISACTIVE と呼ばれる列から導出され、1 (「オン」に対応) または 0 (「オフ」に対応) のいずれかになります。ToggleButton をクリックすると、それに応じてデータベース内の対応する行が更新されます。

しかし、どういうわけか、私の実際の行動はそれとはまったく異なるものです.

ToggleButton をクリックすると、どの行をクリックしたかに関係なく、クリックした行とリストの最初の 2 行の両方に対して 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;
}
4

1 に答える 1

0

トグル ボタンの状態を格納するには、カスタム カーソル アダプタにブール配列を実装する必要があることがわかりました。

于 2013-09-18T17:32:29.967 に答える