Intereting Posts

Android: Как запросить курсор для обновления ListView после удаления строки базы данных?

Это может быть вопрос noob, но я совершенно новый для всего этого SQLite-Database-Cursor-Adapter-ListView-Do-It-Properly-Stuff.

Что у меня есть:

В моей MainActivity меня есть ListView . Я использую SQLite database и заполняю ListView с помощью настраиваемого адаптера, расширяющего SimpleCursorAdapter . Нажимая на элемент в своем ActionBar я активирую Contextual Action Mode . Все работает до сих пор.

Что я хочу:

Щелкнув по определенному значку в ListView item соответствующая строка базы данных должна быть удалена, и ListView должен быть обновлен.

Мой вопрос:

Как обновить свой Cursor и мой ListView правильно? Когда я не использую cursor.requery() в моем OnClickListener и использую cursor = dbm.getIOIOSensorsCursor() вместо этого получаю CursorIndexOutOfBoundsException несколько строк ниже на строке

 int state = cursor.getInt(cursor.getColumnIndex(IOIOSensorSchema.STATE)); 

Мое приложение аварийно завершает работу, но после перезагрузки база данных была удалена, а соответствующий ListView item исчез.

Я думаю, что авария должна иметь какое-то отношение к _position в get getView потому что _position является final . Однако, когда я использую cursor.requery() все работает так, как должно.

Но этот метод устарел, и в документации говорится: «Не используйте это …» . Я хорошо знаком с кодировкой (я все еще новичок и хочу научиться правильно кодировать, а не быстро и грязно) и хочу знать, как это сделать правильно. Я не знаю, важно ли это, но я тестирую свое приложение только на моем (очень быстром) Nexus 4. Кажется, нет проблем с обновлением Cursor достаточно быстро, но мне интересно, будет ли он работать на более медленных устройствах. В случае, если для вас важно, моя база данных будет содержать около 10-20 строк с примерно 12 столбцами. Я думаю, это действительно небольшая база данных.

Вот соответствующий код моего адаптера:

 public class IOIOSensorCursorAdapterCam extends SimpleCursorAdapter { static class ViewHolder { ImageView stateIV, removeIV; TextView nameTV, pinNumberTV, feedIDTV, freqTV; } private Context ctx; private Cursor cursor; private IodDatabaseManager dbm; public IOIOSensorCursorAdapterCam(Context _context, int _layout, Cursor _cursor, String[] _from, int[] _to, int _flags) { super(_context, _layout, _cursor, _from, _to, _flags); ctx = _context; cursor = _cursor; dbm = new IodDatabaseManager(_context); } @Override public View getView(final int _position, View _convertView, ViewGroup _parent) { ViewHolder holder = null; LayoutInflater inflater = (LayoutInflater) ctx .getSystemService(Context.LAYOUT_INFLATER_SERVICE); // There is no view at this position, we create a new one. In this case // by inflating an xml layout. if (_convertView == null) { // Inflate a layout _convertView = inflater.inflate(R.layout.listview_item_sensor_cam, null); holder = new ViewHolder(); holder.stateIV = (ImageView) _convertView .findViewById(R.id.stateImageView); holder.nameTV = (TextView) _convertView .findViewById(R.id.sensorNameTextView); holder.pinNumberTV = (TextView) _convertView .findViewById(R.id.sensorPinNumberTextView); holder.feedIDTV = (TextView) _convertView .findViewById(R.id.sensorFeedIDTextView); holder.freqTV = (TextView) _convertView .findViewById(R.id.sensorFrequencyTextView); holder.removeIV = (ImageView) _convertView .findViewById(R.id.removeImageView); _convertView.setTag(holder); } // We recycle a View that already exists. else { holder = (ViewHolder) _convertView.getTag(); } // Set an OnClickListener to the "Delete Icon" holder.removeIV.setOnClickListener(new OnClickListener() { @SuppressWarnings("deprecation") @Override public void onClick(View _view) { cursor.moveToPosition(_position); // Delete sensor from database here int sensorID = cursor.getInt(cursor .getColumnIndex(IOIOSensorSchema.SENSOR_ID)); dbm.deleteIOIOSensor(sensorID); // This leads to a "CursorIndexOutOfBoundsException" and cannot // be used to refresh the ListView // cursor = dbm.getIOIOSensorsCursor(); // Refresh ListView cursor.requery(); notifyDataSetChanged(); } }); cursor.moveToPosition(_position); if (cursor.getCount() > 0) { int state = cursor.getInt(cursor .getColumnIndex(IOIOSensorSchema.STATE)); if (state == 0) { holder.stateIV.setImageResource(R.drawable.av_play_over_video); holder.stateIV.setColorFilter(ctx.getResources().getColor( R.color.hint_lighter_gray)); // _convertView.setAlpha((float) 0.5); holder.nameTV.setTextColor(ctx.getResources().getColor( R.color.hint_darker_gray)); } else { holder.stateIV.setImageResource(R.drawable.av_pause_over_video); holder.stateIV.setColorFilter(ctx.getResources().getColor( android.R.color.holo_green_light)); // _convertView.setAlpha((float) 1); holder.nameTV.setTextColor(ctx.getResources().getColor( android.R.color.black)); } // Set the sensor's name to the according TextView String sensorName = cursor.getString(cursor .getColumnIndex(IOIOSensorSchema.NAME)); holder.nameTV.setText(sensorName); // Set the sensor's pin number to the according TextView int pinNumber = cursor.getInt(cursor .getColumnIndex(IOIOSensorSchema.PIN_NUMBER)); holder.pinNumberTV.setText("" + pinNumber); // Set the sensor's feed ID to the according TextView int feedID = cursor.getInt(cursor .getColumnIndex(IOIOSensorSchema.FEED_ID)); holder.feedIDTV.setText("" + feedID); // Set the sensor's frequency to the according TextView int frequency = cursor.getInt(cursor .getColumnIndex(IOIOSensorSchema.FREQUENCY)); int timeUnit = cursor.getInt(cursor .getColumnIndex(IOIOSensorSchema.TIME_UNIT)); String frequencyTextViewText = ""; switch (timeUnit) { case IodIOIOSensor.TIME_UNIT_MINUTES: frequencyTextViewText = frequency + " min"; break; case IodIOIOSensor.TIME_UNIT_HOURS: frequencyTextViewText = frequency + " h"; break; default: frequencyTextViewText = frequency + " sec"; break; } holder.freqTV.setText(frequencyTextViewText); } return _convertView; } } 

Редактировать:

Вот мой соответствующий код от OnCickListener после реализации решения:

 // Set an OnClickListener to the "Delete Icon" holder.removeIV.setOnClickListener(new OnClickListener() { @Override public void onClick(View _view) { cursor.moveToPosition(_position); // Delete sensor from database here int sensorID = cursor.getInt(cursor .getColumnIndex(IOIOSensorSchema.SENSOR_ID)); dbm.deleteIOIOSensor(sensorID); Toast.makeText(ctx, R.string.toast_sensor_deleted, Toast.LENGTH_SHORT).show(); // Refresh ListView cursor = dbm.getIOIOSensorsCursor(); swapCursor(cursor); notifyDataSetChanged(); } }); 

Solutions Collecting From Web of "Android: Как запросить курсор для обновления ListView после удаления строки базы данных?"