Android: Wie requery, Cursor-refresh ListView-nach löschen der Datenbank Zeile?
Könnte dies eine noob Frage, aber ich bin ganz neu auf all dies SQLite-Datenbank-Cursor-Adapter-ListView-Machen-Es-Richtig-Zeug.
Was ich habe:
In meinem MainActivity
ich habe eine ListView
. Ich verwende eine SQLite database
und füllen Sie die ListView
mit einem benutzerdefinierten adapter Verlängerung SimpleCursorAdapter
. Durch Klick auf ein Element in meinem ActionBar
ich aktiviere Contextual Action Mode
. Alles funktioniert so weit.
, Was ich will:
Durch klicken auf ein bestimmtes Symbol in meiner ListView item
die nach Datenbank-Zeile gelöscht werden soll, und die ListView
aktualisiert werden soll.
Meine Frage:
Wie aktualisiere ich meine Cursor
und meine ListView
richtig? Wenn ich nicht verwenden cursor.requery()
in meinem OnClickListener
und verwenden cursor = dbm.getIOIOSensorsCursor()
stattdessen bekomme ich eine CursorIndexOutOfBoundsException
ein paar Zeilen weiter unten auf der Linie
int state = cursor.getInt(cursor.getColumnIndex(IOIOSensorSchema.STATE));
Meine app abstürzt, aber nach neu laden der Datenbank gelöscht wurden und die nach ListView item
ist Weg.
Ich denke der Absturz hat etwas damit zu tun, mit _position
get getView
Methode, weil _position
ist final
. Allerdings, wenn ich cursor.requery()
funktioniert alles wie es soll.
Aber diese Methode ist veraltet und es ist die Dokumentation sagt "verwenden Sie nicht dieses...". Ich bin ein Freund von Codierung richtig (ich bin noch Anfänger und will lernen, um code, der richtige Weg und nicht die quick-and-dirty) und wollen wissen, wie Sie dieses Recht tun. Ich weiß nicht, ob es wichtig ist aber ich Teste meine app nur auf meinem (wirklich schnell) Nexus 4. Es scheint keine Probleme bei der Aktualisierung der Cursor
schnell genug, aber ich Frage mich, ob es auch auf langsameren Geräten. In einem Fall ist es wichtig für Sie, meine Datenbank enthält über 10-20 Zeilen mit etwa 12 Spalten. Ich denke, das ist eine sehr kleine Datenbank.
Hier ist der relevante code der meine benutzerdefinierte adapter:
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;
}
}
Edit:
Hier ist mein entsprechender code aus dem OnCickListener nach der Implementierung der Lösung:
//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();
}
});
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sie "aktualisieren Sie [Ihre] Cursor", indem Sie mit dem code wieder zu bekommen, die
Cursor
, mit dem code, den Sie zum erstellen der ursprünglichenCursor
(auf einem hintergrund-thread, bitte). Sie aktualisieren IhreListView
durch den AufrufchangeCursor()
oderswapCursor()
auf dieCursorAdapter
.swapCursor(cursor);
! Ich fügte hinzu, die Lösung zu meinem post.on a background thread, please
. Ich bin neugierig, wenn Sie irgendwelche Gedanken über das tun dies inAsyncTask
vsLoader
?ContentProvider
aus anderen Gründen, verwenden Sie eineCursorLoader
. Sonst, verwenden Sie einfach einenAsyncTask
, IMHO.CursorLoader
AnrufeswapCursor(cursor)
und ein oder mehrere Elemente in einerListView
ausgewählt und die KABINE ist aktiviert? Sollte ich zum Schluss das CAB? Ich mag mich irren, aber ich denke die Nutzer würden denken, es ist ein bisschen seltsam, dass, was auch immer Element, das Sie ausgewählt, wird abgewählt aus dem blauen heraus, weil einContentProvider
festgestellt, einige änderungen in der Datenbank.Loader
Rahmen. IMHO, nur die Aktualisierung der Benutzeroberfläche, wenn der Benutzer ist nicht in der Mitte einer operation.