2013-06-05 27 views
9

Đây có thể là một câu hỏi noob nhưng tôi hoàn toàn mới đối với tất cả SQLite-Database-Cursor-Adapter-ListView-Do-It-Properly-Stuff.Android: Cách yêu cầu một Con trỏ để làm mới ListView sau khi xóa hàng cơ sở dữ liệu?

Những gì tôi có:

Trong MainActivity của tôi, tôi có một ListView. Tôi sử dụng số SQLite database và điền ListView bằng bộ điều hợp tùy chỉnh mở rộng SimpleCursorAdapter. Bằng cách nhấp vào một mục trong số ActionBar của tôi, tôi kích hoạt Contextual Action Mode. Mọi thứ đang hoạt động cho đến nay.

Những gì tôi muốn:

Bằng cách nhấp vào một biểu tượng nào đó trong ListView item hàng cơ sở dữ liệu theo tôi cần xóa và ListView nên được làm mới.

Câu hỏi của tôi:

Làm thế nào để làm mới mình CursorListView tôi đúng? Khi tôi không sử dụng cursor.requery() trong OnClickListener tôi và sử dụng cursor = dbm.getIOIOSensorsCursor() thay vào đó tôi nhận được một CursorIndexOutOfBoundsException một vài dòng dưới đây vào dòng

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

My ứng dụng bị treo, nhưng sau khi tải lại nó trở thành cơ sở dữ liệu đã bị xóa và theo ListView item là Không còn.

Tôi đoán sự cố phải liên quan đến _position trong phương thức getView_positionfinal. Tuy nhiên, khi tôi sử dụng cursor.requery() mọi thứ hoạt động như mong muốn.

Nhưng phương pháp này không được chấp nhận và tài liệu của nó cho biết "Không sử dụng tính năng này ...". Tôi là một người bạn của mã hóa đúng cách (tôi vẫn còn là người mới bắt đầu và muốn học cách viết mã đúng cách và không nhanh chóng và bẩn) và muốn biết làm thế nào để làm điều này đúng. Tôi không biết nếu nó quan trọng nhưng tôi đang thử nghiệm ứng dụng của tôi chỉ trên Nexus (thực sự nhanh) của tôi 4. Có vẻ như không có vấn đề gì với việc làm mới đủ nhanh Cursor, nhưng tôi tự hỏi liệu nó có hoạt động trên các thiết bị chậm hơn không. Trong trường hợp nó quan trọng đối với bạn, cơ sở dữ liệu của tôi sẽ chứa khoảng 10-20 hàng với khoảng 12 cột. Tôi đoán đây là một cơ sở dữ liệu thực sự nhỏ.

Đây là mã có liên quan của bộ chuyển đổi tùy chỉnh của tôi:

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:

Đây là mã có liên quan của tôi từ OnCickListener sau khi thực hiện các giải pháp:

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

Trả lời

15

Làm cách nào để làm mới C của tôi con trỏ và ListView của tôi đúng cách?

Bạn "làm mới [của bạn] Cursor" bằng cách chạy mã của bạn một lần nữa để có được những Cursor, sử dụng mã mà bạn sử dụng để tạo ra các gốc Cursor (trên một sợi nền, xin vui lòng). Bạn làm mới ListView bằng cách gọi changeCursor() hoặc swapCursor() trên số CursorAdapter.

+0

Hoạt động như một sự quyến rũ. Cảm ơn bạn rất nhiều! Vì vậy, tôi chỉ thiếu 'swapCursor (con trỏ);'! Tôi đã thêm giải pháp vào bài đăng của mình. – kaolick

+0

Bạn đề cập đến 'trên chuỗi nền, vui lòng'. Tôi tò mò nếu bạn có bất kỳ suy nghĩ về việc này trong 'AsyncTask' vs một 'Loader'? – theblang

+0

@mattblang: Nếu bạn tình cờ có dữ liệu của bạn được cung cấp bởi một 'ContentProvider' vì các lý do khác, hãy sử dụng' CursorLoader'. Nếu không, chỉ cần sử dụng một 'AsyncTask', IMHO. – CommonsWare

Các vấn đề liên quan