I have a List of contacts with check box.When the user checks the check box i have updated my table field selectedValue with value=1 .Now what i want is i wamna get all the contacts in comma seperated way where selectedValue=1.So for that i have written a query.But my result is not desired.
For eg
I have 4 contacts A,B,C,D in a list.Now if user selects A and C from the list and when i fire that query to get the contacs comma seperated,this is what i get
A,A,C,C
I dont know why 2 values of A and C are comming
Code
public StringBuilder getCheckedContact() {
database = getWritableDatabase();
StringBuilder values = new StringBuilder();
String query = "Select * From " + contactTable + " where " + selectedContact + "=1";
Cursor c = database.rawQuery(query, null);
while (c.moveToNext()) {
for (int i = 0; i < c.getCount(); i++) {
values.append(c.getString(c.getColumnIndexOrThrow(contactName)));
if (i != c.getCount() - 1) {
values.append(",");
}
}
}
c.close();
database.close();
return values;
}
Your while loop loops over the results once, then the for loop loops over the results second time. If you select 4 contacts, you'd get 4*4=16 results.
Why did you add the inner for loop?
This could be rewritten as follows:
public StringBuilder getCheckedContact() {
database = getWritableDatabase();
StringBuilder values = new StringBuilder();
String query = "Select * From " + contactTable + " where " + selectedContact + "=1";
Cursor c = database.rawQuery(query, null);
boolean firstItem = true;
while (c.moveToNext()) {
if(firstItem)
firstItem = false;
else
values.append(",");
values.append(c.getString(c.getColumnIndexOrThrow(contactName)));
}
c.close();
database.close();
return values;
}
I'm trying to load a database column with a cursor result for my quiz app. The reason for this is that i want to populate a list view with the questions in a each category so i set up this:
public void putValues(){
for (int i = 0; i < 18; i++) {
Cursor contentCursor = null;
contentCursor = mDB
.rawQuery("select count(*) from questions_en where used = 0 and category" + " = " + i, null);
if(contentCursor.getCount() >0 )
contentCursor.moveToFirst();
if (contentCursor.isAfterLast()) {
contentCursor.close();
mDB.close();
return;
}
int contentCursorInt = contentCursor.getInt(0);
Cursor upateCursor = null;
upateCursor = mDB.rawQuery("update categories_en set questions_count" + " = " + contentCursorInt + " where " + "_id" + " = " + i, null);
upateCursor.moveToNext();
upateCursor.close();
contentCursor.close();
}
}
so that when the user clicks an answer (on the question screen) used becomes 1(or any non-zero value) the query result changes. The above code works fine the very first time. Because i haven't set up the question screen, i added this query:
public void test(){
Cursor cus = mDB.rawQuery("update questions_en set used = 1 where category = 2 and _id = 146", null);
cus.close();
}
to my DB Adapter and then called this method from my MainActivty
#Override
public void onClick(View v) {
TestAdapter mTest = new TestAdapter(MainActivity.this);
mTest.createDatabase();
mTest.open();
mTest.test();
Log.d(DBHelper.TAG, " Worked ");
mTest.close();
}
});
But when i click on this and go to my ListActivity I expected the value of category 2 to have changed since the query had just been carried out again. But it doesn't reduce. I pulled out my DB from DDMS(file explorer) and i found out that the query to _id = 146 actually didn't change used to 1. Any help on what may be the cause?
Solve the problem with the help of this.
I just changed this:
public void test(){
Cursor cus = mDB.rawQuery("update questions_en set used = 1 where category = 2 and _id = 146", null);
cus.close();
}
to this
public void test(){
int id = 3;
ContentValues data = new ContentValues();
data.put(DBHelper.KEY_USED, "1");
mDB.update(DBHelper.KEY_QUESTIONS_TABLE, data, DBHelper.KEY_ID + " = " + id , null);
}
I'm Parsing a JSON WebService and creating a array with data to INSERT and DELETE entries in a database.
I found the solution bulkInsert to insert multiple rows using database transactions inside a content provider, however, I am trying to do the same procedure to delete multiple lines.
The INSERT solution:
#Override
public int bulkInsert(Uri uri, ContentValues[] allValues) {
SQLiteDatabase sqlDB = mCustomerDB.getWritableDatabase();
int numInserted = 0;
String table = MyDatabase.TABLE;
sqlDB.beginTransaction();
try {
for (ContentValues cv : allValues) {
//long newID = sqlDB.insertOrThrow(table, null, cv);
long newID = sqlDB.insertWithOnConflict(table, null, cv, SQLiteDatabase.CONFLICT_REPLACE);
if (newID <= 0) {
throw new SQLException("Error to add: " + uri);
}
}
sqlDB.setTransactionSuccessful();
getContext().getContentResolver().notifyChange(uri, null);
numInserted = allValues.length;
} finally {
sqlDB.endTransaction();
}
return numInserted;
}
Using this call:
mContext.getContentResolver().bulkInsert(ProviderMyDatabase.CONTENT_URI, valuesToInsertArray);
Is there any way to delete multiple rows (with this array ID's) of database using content provider.
UPDATE:
I found this solution, using the `IN clause:
List<String> list = new ArrayList<String>();
for (ContentValues cv : valuesToDelete) {
Object value = cv.get(DatabaseMyDatabase.KEY_ROW_ID);
list.add(value.toString());
}
String[] args = list.toArray(new String[list.size()]);
String selection = DatabaseMyDatabase.KEY_ROW_ID + " IN(" + new String(new char[args.length-1]).replace("\0", "?,") + "?)";
int total = mContext.getContentResolver().delete(ProviderMyDatabase.CONTENT_URI, selection, args);
LOGD(TAG, "Total = " + total);
The problem is that, if the JSON return more than 1000 rows to insert, occurs error, because the SQLITE_MAX_VARIABLE_NUMBER is set to 999. It can be changed but only at compile time.
ERROR: SQLiteException: too many SQL variables
Thanks in advance
I solved this issue with this code:
if (!valuesToDelete.isEmpty()) {
StringBuilder sb = new StringBuilder();
String value = null;
for (ContentValues cv : valuesToDelete) {
value = cv.getAsString(kei_id);
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(value);
}
String args = sb.toString();
String selection = kei_id + " IN(" + args + ")";
int total = mContext.getContentResolver().delete(uri, selection, null);
LOGD(TAG, "Total = " + total);
} else {
LOGD(TAG, "No data to Delete");
}
Thanks
User ContentResolver object to delete multiple rows.
// get the ContentResolver from a context
// if not from any activity, then you can use application's context to get the ContentResolver
// 'where' is the condition e.g., "field1 = ?"
// whereArgs is the values in string e.g., new String[] { field1Value }
ContentResolver cr = getContentResolver();
cr.delete(ProviderMyDatabase.CONTENT_URI, where, whereArgs);
So any row with (field1 = field1Value) will be deleted.
If you want to delete all the rows then
cr.delete(ProviderMyDatabase.CONTENT_URI, "1 = 1", null);
I am trying, unsucessfully, to query my database to find the maximum 'area number', in my areas table for a certain inspection, so that I can set the text in a form to the next area number.
The database table consists of four columns; _id, inpsection_link, area_number, area-reference.
I have created the following in my database helper class (using this post as a guide: SQLiteDatabase.query method):
public int selectMaxAreaNumber (long inspectionId) {
String inspectionIdString = String.valueOf(inspectionId);
String[] tableColumns = new String[] {
AREA_NUMBER,
"(SELECT max(" + AREA_NUMBER + ") FROM " + AREAS_TABLE + ") AS max"
};
String whereClause = INSPECTION_LINK + " = ?";
String[] whereArgs = new String[] {
inspectionIdString
};
Cursor c = rmDb.query(AREAS_TABLE, tableColumns, whereClause, whereArgs,
null, null, null);
int maxAreaNumber = c.getColumnIndex("max");
return maxAreaNumber;
}
Which I then call in the areaEdit class as follows:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
rmDbHelper = new RMDbAdapter(this);
rmDbHelper.open();
Intent i = getIntent();
inspectionId = i.getLongExtra("Intent_InspectionID", -1);
areaId = i.getLongExtra("Intent_AreaID", -1);
if (areaId == -1) {
nextAreaNumber = rmDbHelper.selectMaxAreaNumber(inspectionId) + 1;
Toast.makeText(getApplicationContext(), String.valueOf(nextAreaNumber),
Toast.LENGTH_LONG).show();
}
setContentView(R.layout.edit_area);
setUpViews();
populateFields();
setTextChangedListeners();
}
However, it just returns 1 everytime (even if there are numbers higher than that stored in the database).
Confused.com!! Any help much appreciated.
Your issue is here :
int maxAreaNumber = c.getColumnIndex("max");
You're getting the column index of max, which is 1 because you only have one column in your query.
Instead, do something like this :
int maxAreaNumber = 0;
if(c.moveToFirst())
{
maxAreaNumber = c.getInt(1);
// or cleaner
maxAreaNumber = c.getInt(c.getColumnIndex("max"));
}
else
// no data in cursor
In my project getting contacts is taking a long time to load.
What are ways to reduce the time of getting contacts
Assume there are 1000 contacts in my phone.
Right now it is taking more than 2 minutes to load all the contacts
How can I reduce the time to load contacts ?
Any Thoughts?
I referred to the the following link when programming the initial method.
http://www.coderzheaven.com/2011/06/13/get-all-details-from-contacts-in-android/
BETTER SOLUTION HERE.....
private static final String[] PROJECTION = new String[] {
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER
};
.
.
.
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null);
if (cursor != null) {
try {
final int nameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
final int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
String name, number;
while (cursor.moveToNext()) {
name = cursor.getString(nameIndex);
number = cursor.getString(numberIndex);
}
} finally {
cursor.close();
}
}
CHEERS...:)
Total time will depend upon what fields you are trying to access from the Contacts table.
Accessing less field means less looping , less processing and hence faster results.
Also to speed up your contacts fetch operation you can use the ContentProvideClient instead of calling query on ContentResolver every time. This will make you query the specific table rather than querying first for the required ContentProvider and then to table.
Create an instance of ContentProviderClient
ContentResolver cResolver=context.getContextResolver();
ContentProviderClient mCProviderClient = cResolver.acquireContentProviderClient(ContactsContract.Contacts.CONTENT_URI);
Then reuse this mCProviderClient to get Contacts(data from any ContentProvider) data on your call.
For example in following method, I am accessing only one field.
private ArrayList<String> fetchContactsCProviderClient()
{
ArrayList<String> mContactList = null;
try
{
Cursor mCursor = mCProviderClient.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (mCursor != null && mCursor.getCount() > 0)
{
mContactList = new ArrayList<String>();
mCursor.moveToFirst();
while (!mCursor.isLast())
{
String displayName = mCursor.getString(mCursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
mContactList.add(displayName);
mCursor.moveToNext();
}
if (mCursor.isLast())
{
String displayName = mCursor.getString(mCursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
mContactList.add(displayName);
}
}
mCursor.close();
}
catch (RemoteException e)
{
e.printStackTrace();
mContactList = null;
}
catch (Exception e)
{
e.printStackTrace();
mContactList = null;
}
return mContactList;
}
Load Contact faster like other apps doing.
I have tested this code with multiple contacts its working fine and faster like other apps within 500 ms (within half second or less) I am able to load 1000+ contacts.
Total time will depend upon what fields you are trying to access from the Contacts table.
Mange your query according to your requirement do not access unwanted fields. Accessing less field means less looping , less processing and hence faster results.
Accessing right table in contact it also help to reduce contact loading time.
Query Optimization to load contact more faster use projection
String[] projection = {
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.PHOTO_URI,
ContactsContract.Contacts.STARRED,
ContactsContract.RawContacts.ACCOUNT_TYPE,
ContactsContract.CommonDataKinds.Contactables.DATA,
ContactsContract.CommonDataKinds.Contactables.TYPE
};
Selection and selection argument
String selection = ContactsContract.Data.MIMETYPE + " in (?, ?)" + " AND " /*+ ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + 1 + "' AND "*/ +
ContactsContract.Data.HAS_PHONE_NUMBER + " = '" + 1 + "'";
String[] selectionArgs = {
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
};
To order contacts alphabetically use following code
try {
Collections.sort(listview_address, new Comparator<ContactBook>() {
#Override
public int compare(ContactBook lhs, ContactBook rhs) {
return lhs.name.toUpperCase().compareTo(rhs.name.toUpperCase());
}
});
} catch (Exception e) {
e.printStackTrace();
}
Following is complete source code
public void initeContacts() {
List<ContactBook> listview_address = new LinkedList<ContactBook>();
SparseArray<ContactBook> addressbook_array = null;
{
addressbook_array = new SparseArray<ContactBook>();
long start = System.currentTimeMillis();
String[] projection = {
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.PHOTO_URI,
ContactsContract.Contacts.STARRED,
ContactsContract.RawContacts.ACCOUNT_TYPE,
ContactsContract.CommonDataKinds.Contactables.DATA,
ContactsContract.CommonDataKinds.Contactables.TYPE
};
String selection = ContactsContract.Data.MIMETYPE + " in (?, ?)" + " AND " /*+ ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + 1 + "' AND "*/ +
ContactsContract.Data.HAS_PHONE_NUMBER + " = '" + 1 + "'";
String[] selectionArgs = {
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
};
String sortOrder = ContactsContract.Contacts.SORT_KEY_ALTERNATIVE;
Uri uri = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
uri = ContactsContract.CommonDataKinds.Contactables.CONTENT_URI;
} else {
uri = ContactsContract.Data.CONTENT_URI;
}
// we could also use Uri uri = ContactsContract.Data.CONTENT_URI;
// we could also use Uri uri = ContactsContract.Contact.CONTENT_URI;
Cursor cursor = getActivity().getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
final int mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE);
final int idIdx = cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID);
final int nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
final int dataIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Contactables.DATA);
final int photo = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Contactables.PHOTO_URI);
final int typeIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Contactables.TYPE);
final int account_type = cursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_TYPE);
while (cursor.moveToNext()) {
int contact_id = cursor.getInt(idIdx);
String photo_uri = cursor.getString(photo);
String contact_name = cursor.getString(nameIdx);
String contact_acc_type = cursor.getString(account_type);
int contact_type = cursor.getInt(typeIdx);
String contact_data = cursor.getString(dataIdx);
ContactBook contactBook = addressbook_array.get(contact_id);
/* if (contactBook == null) {
//list contact add to avoid duplication
//load All contacts fro device
//to add contacts number with name add one extra veriable in ContactBook as number and pass contact_data this give number to you (contact_data is PHONE NUMBER)
contactBook = new ContactBook(contact_id, contact_name, getResources(), photo_uri, contact_acc_type, "phone number");
addressbook_array.put(contact_id, contactBook);
listview_address.add(contactBook);
}*/
String Contact_mimeType = cursor.getString(mimeTypeIdx);
//here am checking Contact_mimeType to get mobile number asociated with perticular contact and email adderess asociated
if (Contact_mimeType.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
if (contactBook != null) {
contactBook.addEmail(contact_type, contact_data);
}
} else {
if (contactBook == null) {
//list contact add to avoid duplication
//load All contacts fro device
//to add contacts number with name add one extra veriable in ContactBook as number and pass contact_data this give number to you (contact_data is PHONE NUMBER)
contactBook = new ContactBook(contact_id, contact_name, getResources(), photo_uri, contact_acc_type, "phone number");
addressbook_array.put(contact_id, contactBook);
listview_address.add(contactBook);
}
// contactBook.addPhone(contact_type, contact_data);
}
}
cursor.close();
try {
Collections.sort(listview_address, new Comparator<ContactBook>() {
#Override
public int compare(ContactBook lhs, ContactBook rhs) {
return lhs.name.toUpperCase().compareTo(rhs.name.toUpperCase());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
You can use following code in above code that I have commented .It club the the single contact with its multiple number.To get all number associated with single contact use array in Object class.
if (contactBook == null) {
//irst contact add to avoid duplication
//load All contacts fro device
contactBook = new ContactBook(contact_id, contact_name, getResources(), photo_uri, contact_acc_type, "");
addressbook_array.put(contact_id, contactBook);
listview_address.add(contactBook);
}
String Contact_mimeType = cursor.getString(mimeTypeIdx);
//here am checking Contact_mimeType to get mobile number asociated with perticular contact and email adderess asociated
if (Contact_mimeType.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
contactBook.addEmail(contact_type, contact_data);
} else {
contactBook.addPhone(contact_type, contact_data);
}
Object class
public class ContactBook {
public int id;
public Resources res;
public String name;
public String photo;
public String contact_acc_type;
public SparseArray<String> emails;
public SparseArray<String> phones;
/* public LongSparseArray<String> emails;
public LongSparseArray<String> phones;*/
public String header = "";
public ContactBook(int id, String name, Resources res, String photo, String contact_acc_type, String header) {
this.id = id;
this.name = name;
this.res = res;
this.photo = photo;
this.contact_acc_type = contact_acc_type;
this.header = header;
}
#Override
public String toString() {
return toString(false);
}
public String toString(boolean rich) {
//testing method to check ddata
SpannableStringBuilder builder = new SpannableStringBuilder();
if (rich) {
builder.append("id: ").append(Long.toString(id))
.append(", name: ").append("\u001b[1m").append(name).append("\u001b[0m");
} else {
builder.append(name);
}
if (phones != null) {
builder.append("\n\tphones: ");
for (int i = 0; i < phones.size(); i++) {
int type = (int) phones.keyAt(i);
builder.append(ContactsContract.CommonDataKinds.Phone.getTypeLabel(res, type, ""))
.append(": ")
.append(phones.valueAt(i));
if (i + 1 < phones.size()) {
builder.append(", ");
}
}
}
if (emails != null) {
builder.append("\n\temails: ");
for (int i = 0; i < emails.size(); i++) {
int type = (int) emails.keyAt(i);
builder.append(ContactsContract.CommonDataKinds.Email.getTypeLabel(res, type, ""))
.append(": ")
.append(emails.valueAt(i));
if (i + 1 < emails.size()) {
builder.append(", ");
}
}
}
return builder.toString();
}
public void addEmail(int type, String address) {
//this is the array in object class where i am storing contact all emails of perticular contact (single)
if (emails == null) {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
emails = new SparseArray<String>();
emails.put(type, address);
/*} else {
//add emails to array below Jelly bean //use single array list
}*/
}
}
public void addPhone(int type, String number) {
//this is the array in object class where i am storing contact numbers of perticular contact
if (phones == null) {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
phones = new SparseArray<String>();
phones.put(type, number);
/* } else {
//add emails to array below Jelly bean //use single array list
}*/
}
}}
For loading the contacts with mininum time the optimum solution is to use the concept of projection and selection argument while querying the cursor for contacts.
this can be done in following way
void getAllContacts() {
long startnow;
long endnow;
startnow = android.os.SystemClock.uptimeMillis();
ArrayList arrContacts = new ArrayList();
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER;
Cursor cursor = ctx.getContentResolver().query(uri, new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.Contacts._ID}, selection, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
cursor.moveToFirst();
while (cursor.isAfterLast() == false) {
String contactNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
int phoneContactID = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID));
int contactID = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));
Log.d("con ", "name " + contactName + " " + " PhoeContactID " + phoneContactID + " ContactID " + contactID)
cursor.moveToNext();
}
cursor.close();
cursor = null;
endnow = android.os.SystemClock.uptimeMillis();
Log.d("END", "TimeForContacts " + (endnow - startnow) + " ms");
}
With above method it took 400ms(less than second) to load contacts where as in normall way it was taking 10-12 sec.
For details imformation this post might help as i took help from it
http://www.blazin.in/2016/02/loading-contacts-fast-from-android.html
If your time increases with your data, then you are probably running a new query to fetch phones/emails for every contact. If you query for the phone/email field using ContactsContract.CommonDataKinds.Phone.NUMBER, then you will just retrieve 1 phone per contact.
The solution is to project the fields and join them by contact id.
Here is my solution in Kotlin (extracting id, name, all phones and emails):
val projection = arrayOf(
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Contactables.DATA
)
val selection = "${ContactsContract.Data.MIMETYPE} in (?, ?)"
val selectionArgs = arrayOf(
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
val contacts = applicationContext
.contentResolver
.query(ContactsContract.Data.CONTENT_URI, projection, selection, selectionArgs, null)
.run {
if (this == null) {
throw IllegalStateException("Cursor null")
}
val contactsById = mutableMapOf<String, LocalContact>()
val mimeTypeField = getColumnIndex(ContactsContract.Data.MIMETYPE)
val idField = getColumnIndex(ContactsContract.Data.CONTACT_ID)
val nameField = getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)
val dataField = getColumnIndex(ContactsContract.CommonDataKinds.Contactables.DATA)
while (moveToNext()) {
val mimeType = getString(mimeTypeField)
val id = getString(idField)
var contact = contactsById[id]
if (contact == null) {
val name = getString(nameField)
contact = LocalContact(id = id, fullName = name, phoneNumbers = listOf(), emailAddresses = listOf())
}
val data = getString(dataField)
when(getString(mimeTypeField)) {
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ->
contact = contact.copy(emailAddresses = contact.emailAddresses + data)
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ->
contact = contact.copy(phoneNumbers = contact.phoneNumbers + data)
}
contactsById[id] = contact
}
close()
contactsById.values.toList()
}
And for reference, my LocalContact model:
data class LocalContact(
val id: String,
val fullName: String?,
val phoneNumbers: List<String>,
val emailAddresses: List<String>
)
I think this is a better solution:
public ContentValues getAllContacts() {
ContentValues contacts = new ContentValues();
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur != null && cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (cur.getInt(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) {
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[]{id}, null);
if (pCur != null) {
while (pCur.moveToNext()) {
String phoneNo = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contacts.put(phoneNo, name);
}
pCur.close();
}
}
}
cur.close();
}
return contacts;
}
for use it you need to call this lines once:
ContentValues contacts = new ContentValues();
contacts = getAllContacts();
and when you want to get contact name by number, just use:
String number = "12345";
String name = (String) G.contacts.get(number);
this algorithm is a bit faster...