2013-06-05 33 views
9

To może być pytanie typu noob, ale jestem całkiem nowy w tym SQLite-Database-Cursor-Adapter-ListView-Do-It-Prototyp-Stuff.Android: Jak zażądać od Cursora odświeżenia ListView po usunięciu wiersza bazy danych?

Co mam:

W moim MainActivity mam ListView. Używam SQLite database i zapełniam ListView z niestandardowym adapterem rozszerzającym SimpleCursorAdapter. Klikając element w mojej ActionBar aktywuję Contextual Action Mode. Wszystko działa do tej pory.

Czego chcę:

Klikając na pewną ikonę w moim ListView item zgodnie z rzędu bazy danych powinny być usunięte i ListView powinny być odświeżane.

Moje pytanie:

Jak odświeżyć mój Cursor i mój ListView prawidłowo? Kiedy nie używać cursor.requery() w moim OnClickListener i używać cursor = dbm.getIOIOSensorsCursor() zamiast ja dostać CursorIndexOutOfBoundsException kilka wierszy poniżej w wierszu

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

My awarii aplikacji, ale po przeładunku to baza danych została usunięta, a według ListView item jest odszedł.

Zgaduję, że katastrofa musi mieć coś wspólnego z _position w metodzie getView, ponieważ _position jest final. Jednak gdy używam cursor.requery(), wszystko działa tak, jak powinno.

Ale ta metoda jest nieaktualna, a jej dokumentacja mówi: "Nie używaj tego ...". Jestem przyjacielem kodowania poprawnie (wciąż jestem początkującym i chcę nauczyć się kodować właściwą drogę, a nie szybkie i brudne) i chcę wiedzieć, jak to zrobić dobrze. Nie wiem, czy to ważne, ale testuję swoją aplikację tylko na moim (naprawdę szybkim) Nexusie 4. Wydaje się, że nie ma problemów z odświeżeniem Cursor wystarczająco szybko, ale zastanawiam się, czy będzie działać na wolniejszych urządzeniach. W przypadku, gdy jest to dla Ciebie ważne, moja baza danych będzie zawierać około 10-20 wierszy z około 12 kolumnami. Sądzę, że to naprawdę mała baza danych.

Oto odpowiedni kod mojego niestandardowego adaptera:

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:

Oto moja odpowiedni kod z OnCickListener po wdrożeniu rozwiązanie:

// 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(); 
    } 
}); 

Odpowiedz

15

Jak odświeżyć moje C ursor i mój ListView właściwie?

You „odświeżyć [swoją] Kursor” uruchamiając swój kod ponownie, aby uzyskać Cursor, stosując kod użyty do utworzenia oryginału Cursor (w wątku tła, proszę). Odświeżysz swój ListView, dzwoniąc pod numer changeCursor() lub swapCursor() na CursorAdapter.

+0

Działa jak urok. Dziękuję bardzo! Tak więc brakowało mi tylko 'swapCursor (cursor);'! Dodałem rozwiązanie do mojego postu. – kaolick

+0

Wspominasz 'na tle wątku, proszę'. Jestem ciekawy, czy masz jakieś przemyślenia na temat tego w 'AsyncTask' vs' Loader'? – theblang

+0

@mattblang: Jeśli zdarzy ci się, że twoje dane są dostarczane przez "ContentProvider" z innych powodów, użyj 'CursorLoader'. W przeciwnym razie użyj 'AsyncTask', IMHO. – CommonsWare