Populating a List from a SQLite Database using “=” operator?
-
21-12-2019 - |
Question
I am running into an issue where I cannot get the screen to dynamically update after I "swipe-to-dismiss" an item from my list. The objects are successfully deleted from the database, but since the screen never updates it gives me the ability to keep swiping to dismiss and eventually causes an IndexOutOfBoundsException.
I have tried every combination of .remove(), .notifyDataSetChanged(), and I am to the point where I am trying to look into other options.
Do you think that my problem may be stemming from the way that I am populating the List lstEvents? ... I am using a lstEvents = db.getAllContacts();
THE MAIN ACTIVITY REFLECTS WORKING CODE
MainActivity
public class MainActivity extends ListActivity implements OnClickListener {
List<Event> lstEvents = new ArrayList<Event>();
EventAdapter adapter;
DatabaseHandler db;
// detail view
TextView tvTitle, tvTime, tvDate;
ImageView ivPic;
ImageButton add;
String title;
String date;
String time;
Context context;
static final int PICK_CONTACT_REQUEST = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// // get detail controls
tvTitle = (TextView) findViewById(R.id.textViewTitle);
tvDate = (TextView) findViewById(R.id.textViewDate);
tvTime = (TextView) findViewById(R.id.textViewTime);
ivPic = (ImageView) findViewById(R.id.imageView1);
add = (ImageButton) findViewById(R.id.add);
add.setOnClickListener(this);
// /////////////////////////////DATABASE/////////////////////////////////////////////
db = new DatabaseHandler(this);
// /////////////////////////////DATABASE/////////////////////////////////////////////
// ///////////////////////////////LISTVIEW////////////////////////////////////////
// Create the adapter to convert the array to views
adapter = new EventAdapter(this, lstEvents);
// attach adapter to a list view
ListView listView = getListView();
listView.setAdapter(adapter);
context = this;
SwipeDismissListViewTouchListener touchListener = new SwipeDismissListViewTouchListener(
listView,
new SwipeDismissListViewTouchListener.DismissCallbacks() {
// DatabaseHandler db = new DatabaseHandler(context);
// EventAdapter adapter = new EventAdapter(context,
// lstEvents);
@Override
public boolean canDismiss(int position) {
return true;
}
@Override
public void onDismiss(ListView listView,
int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
Event event = adapter.getItem(position);
adapter.remove(event);
db.deleteEvent(event);
for (Event ev : db.getAllContacts()) {
String log = "Id: " + ev.get_Id() + " ,Title: "
+ ev.get_title() + " ,Date: " + ev.get_date()
+ " ,RESOURCEID: " + ev.get_image();
// Writing Contacts to log
Log.e("````````````````ON DISMISS`````````````` ", log);
}
}
adapter.notifyDataSetChanged();
}
});
listView.setOnTouchListener(touchListener);
// Setting this scroll listener is required to ensure that during
// // ListView scrolling,
// // we don't look for swipes.
listView.setOnScrollListener(touchListener.makeScrollListener());
lstEvents = db.getAllContacts();
adapter.clear();
adapter.addAll(lstEvents);
adapter.notifyDataSetChanged();
for (Event ev : db.getAllContacts()) {
String log = "Id: " + ev.get_Id() + " ,Title: "
+ ev.get_title() + " ,Date: " + ev.get_date()
+ " ,RESOURCEID: " + ev.get_image();
// Writing Contacts to log
Log.e("++++++++++++++++ONCREATE+++++++++++++++ ", log);
}
}
// @Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
adapter.clear();
lstEvents = db.getAllContacts();
adapter.addAll(lstEvents);
adapter.notifyDataSetChanged();
for (Event ev : db.getAllContacts()) {
String log = "Id: " + ev.get_Id() + " ,Title: "
+ ev.get_title() + " ,Date: " + ev.get_date()
+ " ,RESOURCEID: " + ev.get_image();
// Writing Contacts to log
Log.e("++++++++++++++++ONRESUME+++++++++++++++ ", log);
}
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.add:
Intent intent = new Intent(this, CreateActivity.class);
startActivityForResult(intent, 100);
break;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// attach adapter to a list view
ListView listView = getListView();
listView.setAdapter(adapter);
if (requestCode == 100) {
if (resultCode == RESULT_OK) {
Bundle b = data.getExtras();
title = b.getString("TITLE");
time = b.getString("TIME");
date = b.getString("DATE");
Bitmap bitmap = b.getParcelable("BITMAP");
// ///CONVERTING A BITMAP TO A BYTE[]
byte[] image = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
image = bos.toByteArray();
// ///////
// /////////////////////////////DATABASE/////////////////////////////////////////////
/**
* CRUD OPERATIONS
*/
Log.e("Insert: ", "Inserting ..");
db.addEvent(new Event((int) Math.floor(Math.random() * 101),
title, time, date, image));
// Reading all contacts
Log.e("Reading: ", "Reading all contacts..");
lstEvents = db.getAllContacts();
adapter.clear();
adapter.addAll(lstEvents);
adapter.notifyDataSetChanged();
// logging all events
for (Event ev : db.getAllContacts()) {
String log = "Id: " + ev.get_Id() + " ,Title: "
+ ev.get_title() + " ,Date: " + ev.get_date()
+ " ,RESOURCEID: " + ev.get_image();
// Writing Contacts to log
Log.e("-----------------ON ACTIVITY RESULT-------------- ", log);
}
// /////////////////////////////DATABASE/////////////////////////////////////////////
}
}
}
}
EventAdapter
public class EventAdapter extends ArrayAdapter<Event> {
// View lookup cache
private static class ViewHolder {
//adding drawable to imageview
ImageView img;
TextView title;
TextView time;
TextView date;
}
public EventAdapter(Context context, List<Event> objects) {
super(context, R.layout.date_detail, objects);
// TODO Auto-generated constructor stub
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
Event event = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.date_detail, parent, false);
viewHolder.title = (TextView) convertView
.findViewById(R.id.textViewTitle);
viewHolder.time = (TextView) convertView
.findViewById(R.id.textViewTime);
viewHolder.date = (TextView) convertView
.findViewById(R.id.textViewDate);
//adding drawable to imageview
viewHolder.img = (ImageView) convertView
.findViewById(R.id.imageView1);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
// Populate the data into the template view using the data object
viewHolder.title.setText(event._title);
viewHolder.time.setText(event._time);
viewHolder.date.setText(event._date);
//convert from byte array to bitmap
Bitmap bitmap = convertByteArrayToBitmap(event._image);
// CONVERT BITMAP TO DRAWABLE
viewHolder.img.setImageBitmap(bitmap);
// Return the completed view to render on screen
return convertView;
}
public static Bitmap convertByteArrayToBitmap(
byte[] byteArrayToBeCOnvertedIntoBitMap)
{
Bitmap bitmap = BitmapFactory.decodeByteArray(
byteArrayToBeCOnvertedIntoBitMap, 0,
byteArrayToBeCOnvertedIntoBitMap.length);
return bitmap;
}
}
DATABASE HANDLER
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
String CREATE_EVENTS_TABLE = "CREATE TABLE " + TABLE_EVENTS + "("
+ KEY_ID + " INTEGER," + KEY_TITLE + " TEXT,"
+ KEY_TIME + " TEXT," + KEY_DATE + " TEXT," + KEY_IMAGE + " BLOB" + ")";
db.execSQL(CREATE_EVENTS_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_EVENTS);
// Create tables again
onCreate(db);
}
/**
* All CRUD(Create, Read, Update, Delete) Operations
*/
//adding an event (NEEDS TO ADD DRAWABLE)
public void addEvent(Event event) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, event.get_Id()); //Event ID
values.put(KEY_TITLE, event.get_title()); // Event Title
values.put(KEY_TIME, event.get_time()); // Event Time
values.put(KEY_DATE, event.get_date()); // Event Date
values.put(KEY_IMAGE, event.get_image()); // Event RESOURCEID
// Inserting Row
db.insert(TABLE_EVENTS, null, values);
db.close(); // Closing database connection
}
// Getting single contact
public Event getEvent(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_EVENTS, new String[] { KEY_ID,
KEY_TITLE, KEY_TIME, KEY_DATE, KEY_IMAGE }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
Event event = new Event(Integer.parseInt(cursor.getString(0)),
cursor.getString(1), cursor.getString(2), cursor.getString(3), cursor.getBlob(4));
// return contact
return event;
}
// Getting All Contacts
public List<Event> getAllContacts() {
List<Event> eventList = new ArrayList<Event>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_EVENTS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Event event = new Event();
event.set_Id(Integer.parseInt(cursor.getString(0)));
event.set_title(cursor.getString(1));
event.set_time(cursor.getString(2));
event.set_date(cursor.getString(3));
event.set_image(cursor.getBlob(4));
eventList.add(event);
} while (cursor.moveToNext());
}
// return contact list
return eventList;
}
// Getting event Count
public int getEventsCount() {
String countQuery = "SELECT * FROM " + TABLE_EVENTS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
cursor.close();
// return count
return cursor.getCount();
}
// Updating single contact
public int updateEvent(Event event) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_TITLE, event.get_title());
values.put(KEY_TIME, event.get_time());
values.put(KEY_DATE, event.get_date());
// updating row
return db.update(TABLE_EVENTS, values, KEY_ID + " = ?",
new String[] { String.valueOf(event.get_Id()) });
}
// Deleting single contact
public void deleteEvent(Event event) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_EVENTS, KEY_ID + " = ?",
new String[] { String.valueOf(event.get_Id()) });
db.close();
}
Solution
The problem is that you're defining a second adapter
variable, here
SwipeDismissListViewTouchListener touchListener = new SwipeDismissListViewTouchListener(listView,
new SwipeDismissListViewTouchListener.DismissCallbacks()
{
DatabaseHandler db = new DatabaseHandler(context);
EventAdapter adapter = new EventAdapter(context, lstEvents); // <--
The ListView is bound to the "old" adapter. By changing the contents of lstEvents
, you're basically changing the "true" adapter's backing array, without notifying it of the changes.
The fix would be to remove those instances, and then just using this to delete:
Event evt = adapter.getItem(position);
db.deleteEvent(evt); // to delete from the DB
adapter.remove(evt); // to remove from the adapter
That should work (ArrayAdapter.remove()
calls notifyDataSetChanged()
automatically). Do not delete from both the adapter
and lstEvents
, since those actually point to the same data.