Đâ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 Cursor
và ListView
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
vì _position
là final
. 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();
}
});
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
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
@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