Update ListView after delete operation - android

I am displaying data pulled from the Android OS sqlite database. I am successfully getting the items to delete when I click on them. However I am having an issue refreshing, or updating the listview after the operation.
Below is the code where I delete the contact.
deleteBtn = (Button)v.findViewById(R.id.deleteBtn);
deleteBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Deleted: " + c.getId() + " " + c.getName(), Toast.LENGTH_SHORT).show();
adapter.deleteContact(c.getId());
updateList();
}
});
Below is the updateList() method:
public void updateList(){
myList.refreshDrawableState();
myList.invalidateViews();
this.notifyDataSetChanged();
}
I included in this method all three ways I tried to refresh but none worked for me. Any idea how I might achieve this?
EDIT: I changed my code thinking this would be the solution but it did not work either:
DbAdapter class delete method():
public boolean deleteContact(int rowId){
getAllContactsList();
return db.delete(DB_TABLE, COLUMN_ID + "=" + rowId, null) > 0;
}
getAllContactsList():
public List<Contact> getAllContactsList(){
List<Contact> contactList = new ArrayList();
Cursor c = db.query(DB_TABLE, new String [] {COLUMN_ID, COLUMN_FNAME, COLUMN_LNAME}, null, null, null, null, null);
//loop through cursor rows and add to list
if(c.moveToFirst()){
do{
Contact contact = new Contact();
contact.setId(Integer.parseInt(c.getString(0)));
contact.setfName(c.getString(1));
contact.setlName(c.getString(2));
contactList.add(contact);
}while(c.moveToNext());
}
return contactList;
}public List<Contact> getAllContactsList(){
List<Contact> contactList = new ArrayList();
Cursor c = db.query(DB_TABLE, new String [] {COLUMN_ID, COLUMN_FNAME, COLUMN_LNAME}, null, null, null, null, null);
//loop through cursor rows and add to list
if(c.moveToFirst()){
do{
Contact contact = new Contact();
contact.setId(Integer.parseInt(c.getString(0)));
contact.setfName(c.getString(1));
contact.setlName(c.getString(2));
contactList.add(contact);
}while(c.moveToNext());
}
return contactList;
}
I thought by getting a new cursor before deleting the contact It would update the list accordingly. Unfortunately It made no difference. Any ideas ?

You have to notify the list's adapter that you have modified the underlying data.
Try using adapter.notifyDataSetChanged();

It seems that you have the Database Adapter class, but you're missing the ArrayAdapter class, which is intended to manage the list of items, displayed in your ListView. Take a look at this example, specifically at the WeatherAdapter.java class.
If I am wrong in my assumptions and the adapter object in your code is not a database adapter, but an ArrayAdapter class, try putting adapter.notifyDataSetChanged() instead of this.notifyDataSetChanged().
Let me know if this helped.

You must requery and and generate new list:
public void updateList(){
clear();
addAll(contactsDbHelper.getAllContactsList()); //addAll works since 11 API version.
notifyDataSetChanged(); //need this is you dissabled auto notify
}
P.S. You should done this job with using Content providers and CursorAdapter, but you need manually notify content provider about changes, because Cursor.requery() is deprecated since 11 version.

Related

Android - Remove Duplicate Contacts

I am trying to display contacts in Recycler View everything is working fine but contacts are getting displayed twice or thrice.
Here is the Code
RecyclerView recyclerView;
List<Contacts> contactsList;
ContactsAdapter adapter;
public void getContactList() {
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null,
"UPPER(" + ContactsContract.Contacts.DISPLAY_NAME + ") ASC");
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Contacts contacts = new Contacts(name, number);
if (contactsList.contains(contacts)){
cursor.moveToNext();
}
else {
contactsList.add(contacts);
}
adapter = new ContactsAdapter(contactsList, getApplicationContext());
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
So, how can I solve this problem?
Pass only phoneNumber as a key and phoneName as a value
You can use :
Map<String, String> map = new HashMap<>();
map.put("A", "1");
...
System.out.printf("Before: %s%n", map);
// Set in which we keep the existing values
Set<String> existing = new HashSet<>();
map = map.entrySet()
.stream()
.filter(entry -> existing.add(entry.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.printf("After: %s%n", map);
for example :
Before: {A=1, B=2, C=2, D=3, E=3} After: {A=1, B=2, D=3}
You can change List with HashSet. HashSet prevents to have duplicate items. Your final code should be like that:
RecyclerView recyclerView;
HashSet<Contacts> contactsSet;
ContactsAdapter adapter;
public void getContactList() {
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null,
"UPPER(" + ContactsContract.Contacts.DISPLAY_NAME + ") ASC");
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Contacts contacts = new Contacts(name, number);
contactsSet.add(contacts);
}
List<Contacts> contactsList = new ArrayList<>();
adapter = new ContactsAdapter(contactsList, getApplicationContext());
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
I think there are a couple of questions you should think about. Is the query wrong or is the way I save contacts wrong?
In your app should contacts be allowed to be duplicated? If no you could add a unique constraint to your migration. See Sql Lite Unique Constraints
If your DB should be accepting duplicate values, then you should add a column that signifies the unique ones to that user? Ie userId column or a place the contact is associated with and then add that into your query as Selection and SelectionArgs.
Lastly if you are just looking for a quick fix... you should dive deeper into your filtering.
Your code contactsList.contains(contacts) will never be true because you are always creating the contact on the line above. Then you are checking if your list contains that newly created one. Otherwise you can use the above solution https://stackoverflow.com/a/64535787/5398130
You can override equals() method in class Contacts. This way your contactList.contains(Contact c) can evaluate to true if two contact objects are logically equals from your override method, and thus it will not add it to the list again.
#Override
public boolean equals(Object o){
if(!o.getClass().equals(Contacts.class)) return false;
Contact c2 = (Contact)o;
// if phonenumber is unique to differentiate contact
return c2.number.equals(number);
}
You can follow these steps on this page where i can provide the full solution here is the link

Android - SQLite db keeps showing rows that should have been deleted

I'm currently creating an app that downloads lists from a server and places those lists into an SQLite database. In the Mainactivity it calls the lists from the db and places them into a custom adapter, everything works fine and such.
After this I go through several screens to proces the listdata and in the final activity it uses a query to delete the row it's been working on from the db. I use logcat to print the db after this and it shows that the row has been deleted.
Next it takes me back to the Mainactivity and in its onResume I once again load the lists from the db only to find that the row that should have been deleted is still in it. The listview is being updated correctly, it's really an issue of retrieving data from the database that should have been deleted.
So, anybody has an idea why I get rows that have been deleted in another activity?
Mainactivity:
private List<String> list = new ArrayList<>();
public void onResume() {
super.onResume();
context = getApplicationContext();
ConsLoadListDataSource cllDataSource = new ConsLoadListDataSource(context);
cllDataSource.open();
list = cllDataSource.sqliteToListIds();
cllDataSource.close();
logcat("Jadajada: " + list.toString());
}
SQLiteHelper:
public List<String> sqliteToListIds() {
List<String> conList= new ArrayList<>();
if (!db.isOpen()) {
open();
}
Cursor cursor = db.query(ConsLoadListSQLHelper.TABLE_CONS_HEADER,
allConsListColumns, null, null, "loadlist" , null, "loadlist");
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
conList.add(cursor.getString(1));
cursor.moveToNext();
}
db.close();
return conList;
}
The deleting method works, but since it's being asked for:
public void deleteList(int id) {
if (!db.isOpen()) {
open();
}
db.delete(ConsLoadListSQLHelper.TABLE_CONS_HEADER,
ConsLoadListSQLHelper.CONS_HEADER_ID + " = " + id, null);
db.close();
}
edit
I've found a workaround solution by deleting the row on my server and once again retrieving all data from the server before I go back to my MainActivity, but I still don't know how to solve the original problem and this makes my app more dependent on an internet connection, so it's not perfect, but will have to do for now.
For deleting single item you have to use
public void deleteRule(String value) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(Table_Name, Key_value + " = ?",
new String[] { value });
db.close();
}
Hope it helps.

removing cursor based items in RecyclerView

This is how my recyclerView is coded (partially):
expensesListCursor = dbc.listExpenses(selectedDate);
mLayoutManager = new LinearLayoutManager(getActivity());
rvExpenses.setLayoutManager(mLayoutManager);
rvExpenses.setItemAnimator(new DefaultItemAnimator());
mAdapter = new AdapterExpensesList(expensesListCursor,getActivity());
rvExpenses.setAdapter(mAdapter);
here's how my dbc.ListExpenses is written
public Cursor listExpenses(String date){
Cursor cursor;
cursor = database.query(MySQLiteHelper.TABLE_EXPENSES, new String[] {"rowid as _id", "description, cost"}, "date='" + date + "'", null, null, null, "_id asc");
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
}
and here's how AdapterExpensesList is written
public class AdapterExpensesList extends RecyclerView.Adapter<AdapterExpensesList.ViewHolder> {
Cursor myDataCursor;
public AdapterExpensesList(Cursor expensesListCursor, Context context){
myDataCursor = expensesListCursor;
}
As you can probably see above, the items in my RecyclerView is taken directly from cursor. My problem is now, I'd like to implement the feature to remove some of the data in the RecyclerView. From the examples I found on the net, usually here's how they did it:
private ArrayList<String> mDataset;
public void remove(String item) {
int position = mDataset.indexOf(item);
mDataset.remove(position);
notifyItemRemoved(position);
}
The problem is my data is a cursor object, and cursor doesn't have the .remove(position) like ArrayList for example. So how do I achieve the same thing, that is to remove certain data from certain position?
Note: I just want to remove data from particular (selected) position, and not the data inside the database itself.
You can not delete items from the cursor check it here.
https://stackoverflow.com/a/6724929/5492047
Instead you can convert your cursor items in list https://www.javatpoint.com/java-list or arraylist https://www.javatpoint.com/java-arraylist
and achieve your task.

Displaying Data in The ListView in Android

I am retrieving data from SQLite and trying to display it in the ListView. The problem is I have two columns in the database and the listview only shows data from one column. I am using following code for this purpose
public List<entry> getAllEntries() {
List<Entry> entries = new ArrayList<Entry>();
Cursor cursor = database.query(MySQLiteHelper.TABLE_ENTRIES,
allEntries, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
Entry entry = cursorToEntry(cursor);
Entry entry1 = cursorToEntry(cursor);
Log.d(TAG, "get entry = " + cursorToEntry(cursor).toString());
entries.add(entry);
cursor.moveToNext();
Log.d(TAG, "get amount = "+ cursorToEntries(cursor).toString1());
entries.add(entry1);
cursor.moveToNext();
}
cursor.close();
return entries;
}
And I have also been trying following code
while(cursor.moveToNext())
{
entries.add("Entry"+cursor.getString(1)+"Amount"+cursor.getString(2));
}
And thats how I am displaying it in the ListView
List<Entry> values = datasource.getAllEntries();
ArrayAdapter<Entry> adapter = new ArrayAdapter<Entry>(this,
android.R.layout.simple_list_item_1, values);
setListAdapter(adapter);
}
You can either use a CursorAdapter, which lets you specify a row layout as well as how to map from columns in the cursor to views in the layout; or you can write your own adapter implementation that extends from BaseAdapter and is internally backed by a Cursor. I suggest you watch The World of ListView.

Android: Deleting a row from SQLite table and updating a ListView

I am new to android development and have come across a problem with deleting a row in a SQLite table that I have not been able to find a solution to. When I try to delete a row nothing is happening.
In my activity, called 'MainActivity,' I am using a context menu to call a method to delete an item from the list. This portion of code is as follows:
case R.id.delete_program:
DBAdapter adap = new DBAdapter(this);
adap.open();
long pass = (long) (position + 1);
adap.removeFromCurrent(pass);
adap.close();
Runnable run = new Runnable() {
public void run(){
refreshCurrent(getApplicationContext());
}
};
runOnUiThread(run);
proAdapt.notifyDataSetChanged();
return true;
In 'DBAdapter' the method removeFromCurrent():
public boolean removeFromCurrent(long cp_id) {
return this.dB.delete(PROGRAMS_TABLE, CP_ID + '=' + cp_id, null) > 0;
}
In 'MainActivity' the method refreshCurrent():
public static void refreshCurrent(Context context) {
CURRENT.clear();
DBAdapter adap = new DBAdapter(context);
adap.open();
ArrayList<Program> temp = adap.getCurrentPrograms();
for(Program item : temp) {
Toast.makeText(context, "Item added: " + item.getName(), Toast.LENGTH_SHORT).show();
CURRENT.add(item);
}
adap.close();
}
I'm using the toast to check if the table has changed but the display has not.
From 'DBAdapter' the method getCurrentPrograms():
public ArrayList<Program> getCurrentPrograms() {
ArrayList<Program> list = new ArrayList<Program>();
Cursor cursor =
this.dB.query(PROGRAMS_TABLE, new String[] {
CP_ID, CP_NAME, ACTUAL_DAY, D_ID, CP_CYCLE, CP_DAY_ONE },
null, null, null, null, null);
int rows = cursor.getCount();
if(cursor != null)
cursor.moveToFirst();
for(int i = 1; i <= rows; i++) {
list.add(new Program(cursor.getString(cursor.getColumnIndex(CP_NAME)),
cursor.getInt(cursor.getColumnIndex(ACTUAL_DAY)),
cursor.getInt(cursor.getColumnIndex(CP_DAY_ONE)),
cursor.getInt(cursor.getColumnIndex(CP_CYCLE))));
cursor.moveToNext();
}
return list;
}
The ArrayList 'CURRENT' is the list used to populate the ListView. My thinking was that I would be able to delete a row from the table and then repopulate this list as well as the ListView. I was also curious as to what happened to a SQLite table once a row is removed; do the other rows move up a position, or do they stay in the same place?
I am still very new to this so any help about my problem or tips for the rest of my code would be much appreciated. Let me know what else I'm doing wrong with my programming.
If you are using the SQLiteOpenHelper you should be getting a SQLiteDatabase object and then using a transaction, if you don't set it as successful then nothing will happen
SQLiteDatabase db = mDbHelper.getWritableDatabase();
db.beginTransaction();
//Do stuff
db.setTrasactionSuccessfull();
db.endTransaction();
Also I think when you pass null into the where clause the where doesn't matter.
You should have something like db.delete("tbl", "id=?", new String[]{String.valueOf(id)});

Categories

Resources