Android:删除数据库行后如何重新查询游标刷新ListView?

这可能是一个noob问题,但我对这个SQLite-Database-Cursor-Adapter-ListView-Do-It-Properly-Stuff是个新东西。

我拥有的:

在我的MainActivity我有一个ListView 。 我使用SQLite database并使用扩展SimpleCursorAdapter的自定义适配器填充ListView 。 通过点击我的ActionBar一个项目,我激活Contextual Action Mode 。 一切工作到目前为止。

我想要的是:

通过在我的ListView item点击某个图标,相应的数据库行应该被删除, ListView应该被刷新。

我的问题:

如何正确地刷新我的Cursor和我的ListView ? 当我不在我的OnClickListener使用cursor.requery()并使用cursor = dbm.getIOIOSensorsCursor()我得到了一行CursorIndexOutOfBoundsException

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

我的应用程序崩溃,但重新加载后,数据库已被删除,相应的ListView item不见了。

我猜崩溃必须与_position在get getView方法有关,因为_positionfinal 。 但是,当我使用cursor.requery()一切正常。

但是这个方法已经被废弃了,它的文档说“不要使用这个…” 。 我是一个正确编码的朋友(我还是个初学者,想要学习正确的方法,而不是快速和肮脏的),并想知道如何做到这一点。 我不知道它是否重要,但是我只在我的(非常快)的Nexus 4上testing我的应用程序。看起来没有问题刷新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; } } 

编辑:

这是我实现解决scheme后,从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?"

如何正确地刷新我的光标和我的ListView?

你可以通过再次运行你的代码来获得Cursor ,并使用你创build原始Cursor的代码(在后台线程上)来“刷新你的游标”。 通过调用CursorAdapter上的changeCursor()swapCursor()来刷新ListView