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.
Related
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
i'am getting my Listview data from an sqlite database like this
ArrayAdapter<String> aa;
ArrayList<String> arrayList = new ArrayList<String>();
aa = new ArrayAdapter<String>(getActivity(),
R.layout.row_listview, arrayList);
setListAdapter(aa);
Cursor cursor8 = db.rawQuery("SELECT * FROM test21", null);
if(cursor8.getCount() == 0)
{
textView5.setVisibility(View.VISIBLE);
}cursor8.close();
Cursor cursor = db.rawQuery("SELECT * FROM test21", null);
// Toast.makeText(myContext, ""+cursor.getCount(), Toast.LENGTH_LONG).show();
if(cursor.moveToFirst())
{
do {
arrayList.add(cursor.getString(3));
}
while (cursor.moveToNext());
}
When i click another button it remove all the data of the sqlitedatabase.
How can i refresh the content of the listview because there is now nothing. I always need to go back in the activity each time :(
Get rid of the notifyDataSetChanged() and call requery() on your Cursor. Here is a sample project demonstrating this.
Hope it will works for you.
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.
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.
I'm new in android. I'm facing a problem creating a listview using data from sqlite database.
I found this code below to create a listview from contact data
public class Test extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get a cursor with all people
Cursor c = getContentResolver().query(Contacts.CONTENT_URI,CONTACT_PROJECTION, null, null, null);
startManagingCursor(c);
ListAdapter adapter = new SimpleCursorAdapter(this,
// Use a template that displays a text view
android.R.layout.simple_list_item_1,
// Give the cursor to the list adatper
c,
// Map the NAME column in the people database to...
new String[] {Contacts.DISPLAY_NAME},
// The "text1" view defined in the XML template
new int[] {android.R.id.text1});
setListAdapter(adapter);
}
private static final String[] CONTACT_PROJECTION = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME
};
}
Now I use this code to pull data from database
SQLiteDatabase myDB= null;
String TableName = "myTable";
myDB = this.openOrCreateDatabase("DatabaseName", MODE_PRIVATE, null);
// Get a cursor with all people
Cursor c = myDB.rawQuery("SELECT * FROM " + TableName , null);
Now How can I combine these two codes so I can show data pulled from a database in this list.
Thanks in advance.
If you want to list the data from both sources (contact and DB), I think only option you have is construct an array with return values from both sources.
List finalList = new ArrayList();
Cursor c = getContentResolver().query(Contacts.CONTENT_URI,CONTACT_PROJECTION, null, null, null);
startManagingCursor(c);
c.moveToFirst();
Iterate this cursor and populate the String value to finalList
SQLiteDatabase myDB= null;
String TableName = "myTable";
myDB = this.openOrCreateDatabase("DatabaseName", MODE_PRIVATE, null);
// Get a cursor with all people
Cursor c2 = myDB.rawQuery("SELECT * FROM " + TableName , null);
startManagingCursor(c2);
c2.moveToFirst();
Iterate c2 cursor and add values to finalList.
Convert finalList to array by Iterating finalList
String[] ipArray = new String[finalList.size()];
loop through list and populate the values to ipArray.
I don't have IDE handy, so I have typed the flow.
If suppose you already have data in your cursor, you can follow code in the following tutorial
http://chetanandroidarora.wordpress.com/2011/12/18/customcursoradapter/