I am successfully storing contacts in parse.com dashboard data browser by this code.
public void readContacts(){
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null);
if (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 (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) ==1) {
System.out.println(name );
ParseObject testObject = new ParseObject("Contacts");
testObject.put("names", name);
// get the phone number
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
String phone = pCur.getString(
pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
System.out.println( phone);
testObject.put("phonenumber", phone);
}
pCur.close();
testObject.saveInBackground();
}
}
}
}
But there is no check for the duplicate contacts !
It stores all the contacts duplicate from sim / phone memory.
How can it be avoided ?
One possible method I think is to store distinct names(contact) in local database, & then retrieving that data to store it in parse.com
Is there exists a better way ?
Thanks in advance...
An easy approach could be to load the data to a MatrixCursor with no duplicate data. For example lets assume you have a cursor c1 will many contacts, but you need a cursor with no duplicate data. Here is what you could do:
MatrixCursor mc = new MatrixCursor(new String[] {
Phone._ID,
Phone.DISPLAY_NAME_PRIMARY,
Phone.NUMBER
});
String lastNumber = "";
while(c1.moveToNext()){
String id = c1.getString(c1.getColumnIndexOrThrow(Phone._ID));
String name = c1.getString(c1.getColumnIndexOrThrow(Phone.DISPLAY_NAME_PRIMARY)));
String number = c1.getString(c1.getColumnIndexOrThrow(Phone.NUMBER));
//Some condition to check previous data is not matched and only then add row
if(!lastNumber.contains(number)){
lastNumber = number;
mc.addRow(new String[]{id, name, number});
}
}
c1.close();
Make an instance of MatrixCursor with same columns, and then load if last number or contact name does not match that of the previous contact. The condition for checking is upto you. Query data in some order so that the duplicate contacts stay together first.
Once the MatrixCursor is loaded you can fetch data from it. You could also attach it to a view through a custom CursorLoader or CursorAdapter.
Please see the below method. You will get contacts list which does not have duplicate phone numbers.
public void readContacts() {
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
ArrayList<ParseObject> contacts = new ArrayList<ParseObject>();
ArrayList<String> list = new ArrayList<String>();
if (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 (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) == 1) {
System.out.println(name);
ParseObject testObject = new ParseObject("Contacts");
testObject.put("names", name);
// get the phone number
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { id }, null);
while (pCur.moveToNext()) {
String phone = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
System.out.println(phone);
testObject.put("phonenumber", phone);
if(!list.contains(phone)) {
contacts.add(testObject);
}
list.add(phone);
}
pCur.close();
testObject.saveInBackground();
}
}
}
}
Set is a collection in java that does not allow duplicates. You can put your data into a set with number as a key and name as value, to avoid duplicate numbers.
And later you can take them back from set and put into your testObject with name as key and number as value.
Here is the Solution that i worked out for you....
You can go through the logcat for information about how it works 100%
import java.util.ArrayList;
import android.app.Activity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
public class MainActivity extends Activity {
String ClsSimPhonename = null;
String ClsSimphoneNo = null;
public static ArrayList<String> phonecontact = new ArrayList<String>();
public static ArrayList<String> simcontact = new ArrayList<String>();
public static ArrayList<String> totalcontact = new ArrayList<String>();
public static ArrayList<String> repeatedcontact = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// get phone contact...
getphonecontact();
// get sim contact...
getsimcard_contact();
System.out.println("phone??? " + phonecontact);
System.out.println("sim??? " + simcontact);
System.out.println("sim_size??? " + simcontact.size());
System.out.println("phone_size??? " + phonecontact.size());
System.out.println("totalcontact_size??? " + totalcontact.size());
// filter process beigins here....
nowFilterContact();
}
private void nowFilterContact() {
// TODO Auto-generated method stub
// determine which contact have more item....
if (simcontact.size() > phonecontact.size()) {
onemorefiltermethod(simcontact.size(), simcontact, phonecontact);
} else {
onemorefiltermethod(phonecontact.size(), phonecontact, simcontact);
}
}
private void onemorefiltermethod(int size, ArrayList<String> contacts,
ArrayList<String> contact2) {
// TODO Auto-generated method stub
// compare both contact and get repeated contacts....
for (int i = 0; i < size; i++) {
try {
if (contacts.contains(contact2.get(i))) {
// add repeated contacts to array....
repeatedcontact.add(contact2.get(i));
}
} catch (Exception e) {
}
}
System.out.println("repeatedcontact_size??? " + repeatedcontact.size());
// now delete repeated contact from total contact
now_deletedrepeated_contact_from_total();
}
private void now_deletedrepeated_contact_from_total() {
// TODO Auto-generated method stub
for (int i = 0; i < totalcontact.size(); i++) {
try {
if (totalcontact.contains(repeatedcontact.get(i))) {
totalcontact.remove(repeatedcontact.get(i));
}
} catch (Exception e) {
}
}
System.out.println("Final contact size" + totalcontact.size());
System.out.println("Final contact " + totalcontact);
}
private void getsimcard_contact() {
// TODO Auto-generated method stub
try {
Uri simUri = Uri.parse("content://icc/adn");
Cursor cursorSim = this.getContentResolver().query(simUri, null,
null, null, null);
while (cursorSim.moveToNext()) {
ClsSimPhonename = cursorSim.getString(cursorSim
.getColumnIndex("name"));
ClsSimphoneNo = cursorSim.getString(cursorSim
.getColumnIndex("number"));
ClsSimphoneNo.replaceAll("\\D", "");
ClsSimphoneNo.replaceAll("&", "");
ClsSimPhonename = ClsSimPhonename.replace("|", "");
/*
* add contact from phone to array phone array and total array
*/
phonecontact.add(ClsSimphoneNo);
totalcontact.add(ClsSimphoneNo);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void getphonecontact() {
// TODO Auto-generated method stub
try {
String[] PROJECTION = new String[] { Contacts._ID,
Contacts.DISPLAY_NAME, Phone.NUMBER };
Cursor c = managedQuery(Phone.CONTENT_URI, PROJECTION, null, null,
null);
if (c.moveToFirst()) {
String ClsPhonename = null;
String ClsphoneNo = null;
do {
ClsPhonename = c.getString(c
.getColumnIndex(Contacts.DISPLAY_NAME));
ClsphoneNo = c.getString(c.getColumnIndex(Phone.NUMBER));
/*
* add contact from sim to array sim array and total array
*/
simcontact.add(ClsphoneNo);
totalcontact.add(ClsphoneNo);
ClsphoneNo.replaceAll("\\D", "");
ClsPhonename = ClsPhonename.replaceAll("&", "");
ClsPhonename.replace("|", "");
String ClsPhoneName = ClsPhonename.replace("|", "");
} while (c.moveToNext());
}
} catch (Exception e) {
}
}
}
Permission
<uses-permission android:name="android.permission.READ_CONTACTS"/>
Your output is on now_deletedrepeated_contact_from_total() method.
Check totalcontact array value for Final output
Related
i use of this code that can get contact's number and contact's thumbnail , but this is not suitable and take to long to load and prepare contacts .
please help me to improve performance of this code :
List<Contact_Pojo> list = new ArrayList<Contact_Pojo>();
ContentResolver cr = getActivity().getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null,
null, null, Phone.DISPLAY_NAME + " ASC");
int i = 0;
if (cur.moveToFirst()) {
while (cur.moveToNext()) {
Cursor phoneCursor = getActivity()
.getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[] { ContactsContract.CommonDataKinds.Phone.NUMBER, },
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ " = ?",
new String[] { cur.getString(cur
.getColumnIndex(ContactsContract.Contacts._ID)) },
null);
if (phoneCursor.moveToFirst()) {
Contact_Pojo personContact = new Contact_Pojo();
/*
* Id
*/
personContact.setId(cur.getString(1));
/*
* Name
*/
personContact
.setName(cur.getString(cur
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
/*
* Photo ID
*/
personContact
.setImageUrl(cur.getString(cur
.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI)));
/*
* Number
*/
personContact.setNumber(phoneCursor.getString(0));
//
list.add(personContact);
}
phoneCursor.close();
}
}
cur.close();
return list;
Update 4/4/2015
it is slow because it has getting all column from contact provider , in this table has +20 column that take many time .
How about using AsyncTaskLoader,
write this code when you want to get contacts list
getLoaderManager() or getSupportLoaderManager().initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> loadingCallback)
public class LoadingCallback implements LoaderManager.LoaderCallbacks<Void> {
#Override
public Loader<Void> onCreateLoader(int i, Bundle bundle) {
// Show your dialog;
return new InitializeContactsTask(context, (ArrayList) contactList, mAdapter);
}
#Override
public void onLoadFinished(Loader<Void> voidLoader, Void aVoid) {
// UI Work here after background task and hide dialog.
}
#Override
public void onLoaderReset(Loader<Void> voidLoader) {
}
}
and
public class InitializeApplicationsTask extends AsyncTaskLoader<Void> {
#Override
protected void onStartLoading() {
forceLoad();
}
#Override
public Void loadInBackground() {
// Query the contacts here and return null
return null;
}
}
It's slow because, you are getting all column from contact provider, so use projection to get only those column which are required. like
String[] projection = {
ContactsContract.Contacts.DISPLAY_NAME
// this is just example, add fields that required
} ;
can you please tell me what is purpose of second query ? because here is my result of getting contact
and my method for getting all contact is
#SuppressLint("InlinedApi")
public void readContacts() {
long l1 = System.currentTimeMillis();
Log.d("DEBUG",
"starting readContacts() time " + l1);
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null,
null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
Contact_pojo cp = new Contact_pojo();
String Contact_Id = cur.getString(cur
.getColumnIndex(ContactsContract.Contacts._ID));
String Contact_Name = cur
.getString(cur
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
String photothumb = "";
try {
photothumb = cur
.getString(cur
.getColumnIndex(ContactsContract.Contacts.PHOTO_THUMBNAIL_URI));
if (photothumb != null
&& !photothumb.toString().equalsIgnoreCase("")) {
cp.setImageUri(photothumb);
}
} catch (Exception e) {
e.printStackTrace();
}
cp.setId(Contact_Id);
cp.setName(Contact_Name);
Cursor phones = cr.query(Phone.CONTENT_URI, null,
Phone.CONTACT_ID + " = " + Contact_Id, null, null);
while (phones.moveToNext()) {
String number = phones.getString(phones
.getColumnIndex(Phone.NUMBER));
int type = phones.getInt(phones.getColumnIndex(Phone.TYPE));
Log.d("DEBUG", "number " + number + " type " + type);
cp.setNumber(number);
}
phones.close();
contactList.add(cp);
}
}
long l2 = System.currentTimeMillis();
Log.d("DEBUG",
"Finished readContacts() time " + l2);
Log.d("DEBUG","Total contact loaded "+contactList.size()+" within "+ (l2 - l1) + "ms");
}
Don't use double query, this is taking too much time if device have lots of contacts and it's not working in some device also...
You can also fetch contact with single query..
Use below code..
public void fetchContacts()
{
String[] projection = new String[] {
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.HAS_PHONE_NUMBER,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID};
String _ID = ContactsContract.CommonDataKinds.Phone.CONTACT_ID;
String DISPLAY_NAME = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME;
String NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER;
Cursor cursor = mActivity.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection, ContactsContract.CommonDataKinds.Phone.HAS_PHONE_NUMBER + "=?", new String[] { "1" },
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
System.out.println("contact size.."+cursor.getCount());
if (cursor.getCount() > 0) {
while (cursor.moveToNext()) {
String contact_id = cursor.getString(cursor.getColumnIndex( _ID ));
String name = cursor.getString(cursor.getColumnIndex( DISPLAY_NAME ));
String phoneNumber = cursor.getString(cursor.getColumnIndex(NUMBER));
System.out.println(" name : "+name);
System.out.println(" number : "+phoneNumber);
}
}
}
Check below links for get contact photo.
ContactsContract.Contacts.Photo
Getting a Photo from a Contact
I want user to select a number from calllog and that number get selected and come in the activity. So I created custom calllog list. I used this code but it is not showing the call log list in right order
first thing it is showing the callhistory of the first number fully that it gets in the calllog list
second I wnt to show the name also, I tried a lot but I am not able to do
Can anyone tell what amendments i make in this code to make it right
The code I used is:
String[] callLogFields = { android.provider.CallLog.Calls._ID,
android.provider.CallLog.Calls.NUMBER,
android.provider.CallLog.Calls.CACHED_NAME };
String viaOrder = android.provider.CallLog.Calls.DATE + " DESC";
String WHERE = android.provider.CallLog.Calls.NUMBER + " >0"; /*filter out private/unknown numbers */
final Cursor callLog_cursor = this.getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI, callLogFields,
WHERE, null, viaOrder);
AlertDialog.Builder myversionOfCallLog = new AlertDialog.Builder(this);
android.content.DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int item) {
callLog_cursor.moveToPosition(item);
Log.v("number", callLog_cursor.getString(callLog_cursor
.getColumnIndex(android.provider.CallLog.Calls.NUMBER)));
callLog_cursor.close();
}
};
myversionOfCallLog.setCursor(callLog_cursor, listener,
android.provider.CallLog.Calls.NUMBER);
myversionOfCallLog.setTitle("Choose from Call Log");
myversionOfCallLog.create().show();
You can add the Contact Numbers in a Set, which will prevent adding duplicate contact numbers. Then add the Set's data to listview as you want.
Set<String> setNumbers = new HashSet<String>();
String callNumber = cursor.getString(cursor.getColumnIndex(
android.provider.CallLog.Calls.NUMBER));
setNumbers.add(callNumber);
Hope this helps.
For saving numbers without duplicates, as MysticMagic suggested, use 'Set' as per the link given in the comment.
For getting the contact name from the phone number, use code :
(Reference)
private String getContactName(Context context, String number) {
String name = null;
// define the columns I want the query to return
String[] projection = new String[] {
ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.PhoneLookup._ID};
// encode the phone number and build the filter URI
Uri contactUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
// query time
Cursor cursor = context.getContentResolver().query(contactUri, projection, null, null, null);
if(cursor != null) {
if (cursor.moveToFirst()) {
name = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
Log.v(TAG, "Started uploadcontactphoto: Contact Found # " + number);
Log.v(TAG, "Started uploadcontactphoto: Contact name = " + name);
} else {
Log.v(TAG, "Contact Not Found # " + number);
}
cursor.close();
}
return name;
}
Also refer here for another method to fetch name in phone call history
Uri allCalls = Uri.parse("content://call_log/calls");
Cursor c = managedQuery(allCalls, null, null, null, null);
String num= c.getString(c.getColumnIndex(CallLog.Calls.NUMBER));// for number
String name= c.getString(c.getColumnIndex(CallLog.Calls.CACHED_NAME));// for name
String duration = c.getString(c.getColumnIndex(CallLog.Calls.DURATION));// for duration
int type = Integer.parseInt(c.getString(c.getColumnIndex(CallLog.Calls.TYPE)));// for call type, Incoming or out going
Finally this is the code that worked with the help of MysticMagic and Nishanthi Grashia
Set setA;
setA = new HashSet();
public void getCallLog() {
try {
final String[] projection = null;
final String selection = null;
final String[] selectionArgs = null;
final String sortOrder = "DATE DESC";
final Cursor cursor = this.getContentResolver().query(
Uri.parse("content://call_log/calls"), projection,
selection, selectionArgs, sortOrder);
if (cursor != null) {
// Loop through the call log.
while (cursor.moveToNext()) {
// Common Call Log Items
String callNumber = cursor
.getString(cursor
.getColumnIndex(android.provider.CallLog.Calls.NUMBER));
setA.add(callNumber);
}
generateList();
}
} catch (Exception e) {
}
}
#SuppressLint("NewApi")
private void generateList() {
// TODO Auto-generated method stub
try {
Object[] calllist = new String[setA.size()];
calllist = setA.toArray();
String scalllist[] = Arrays.copyOf(calllist, calllist.length,
String[].class);
for (int i = 0; i < scalllist.length; i++) {
scalllist[i] = scalllist[i] + " "
+ getContactName(this, scalllist[i]);
}
final Dialog d = new Dialog(this);
d.setContentView(R.layout.dialog1);
d.setTitle("Choose from Call Log...");
final ListView lv1 = (ListView) d.findViewById(R.id.listView1);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1,
scalllist);
lv1.setAdapter(adapter);
lv1.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
String clickednumber[] = (lv1.getItemAtPosition(arg2)
.toString()).split(" ");
usernumber.setText(clickednumber[0]);
try {
username.setText(clickednumber[1]);
} catch (ArrayIndexOutOfBoundsException e) {
username.setText(" ");
}
d.dismiss();
}
});
d.show();
} catch (Exception e) {
}
}
private String getContactName(Context context, String number) {
String name = null;
try {
// define the columns I want the query to return
String[] projection = new String[] {
ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.PhoneLookup._ID };
// encode the phone number and build the filter URI
Uri contactUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(number));
// query time
Cursor cursor = context.getContentResolver().query(contactUri,
projection, null, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
name = cursor
.getString(cursor
.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
} else {
name = " ";
}
cursor.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return name;
}
I had written a code to fetch contact name, phone number and image from Contacts and to display it on a listview in android. It's working fine but taking more time to load. I had tried to use multi-threading in some parts of the code. But the loading time is not decreased.
Here is the onCreate() method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvDetail = (ListView) findViewById(R.id.listView1);
fetchcontacts();
lvDetail.setAdapter(new MyBaseAdapter(context, myList));
}
Here is the code for fetch contacts:
private void fetchcontacts() {
// TODO Auto-generated method stub
Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null,
null, null, ContactsContract.Contacts.DISPLAY_NAME + " ASC");
int count = cursor.getCount();
if (count > 0) {
Toast.makeText(context, "count >0", Toast.LENGTH_SHORT).show();
while (cursor.moveToNext()) {
String columnId = ContactsContract.Contacts._ID;
int cursorIndex = cursor.getColumnIndex(columnId);
String id = cursor.getString(cursorIndex);
name = cursor.getString(cursor
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Toast.makeText(context, "Toast 1", Toast.LENGTH_SHORT).show();
int numCount = Integer.parseInt(cursor.getString(cursor
.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)));
if (numCount > 0) {
Toast.makeText(context, "Toast 2", Toast.LENGTH_SHORT).show();
Cursor phoneCursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,
CommonDataKinds.Phone.CONTACT_ID+" = ?", new String[] { id
}, ContactsContract.Contacts.DISPLAY_NAME + " ASC");
while (phoneCursor.moveToNext()) {
Toast.makeText(context, "Toast 3", Toast.LENGTH_SHORT).show();
phoneNo = phoneCursor.getString(phoneCursor
.getColumnIndex(ContactsContract.CommonDataKinds.
Phone.NUMBER));
String image_uri = phoneCursor
.getString(phoneCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_URI));
if (image_uri != null) {
Toast.makeText(context, "Toast 4", Toast.LENGTH_SHORT).show();
System.out.println(Uri.parse(image_uri));
try {
bitmap = MediaStore.Images.Media
.getBitmap(this.getContentResolver(),
Uri.parse(image_uri));
// sb.append("\n Image in Bitmap:" + bitmap);
// System.out.println(bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Toast.makeText(context, name, Toast.LENGTH_SHORT).show();
getDataInList(name,phoneNo,bitmap);
name=null;
phoneNo=null;
Drawable myDrawable = getResources().getDrawable(R.drawable.star1);
bitmap = ((BitmapDrawable) myDrawable).getBitmap();
}
phoneCursor.close();
}
}
}
Here the setAdapter() function of the listview is working after fetching all the contacts to an ArrayList. do anyone have idea about how to display the contacts during fetching contacts? any sample code?
1.Read the Columns from the Cursor which you required only ,According to your requirement you just need _ID,HAS_PHONE_NUMBER,DISPLAY_NAME ,so change the Cursor reading
Cursor cursor = getContentResolver().query(
ContactsContract.Contacts.CONTENT_URI,
new String[] { ContactsContract.Contacts._ID,
ContactsContract.Contacts.HAS_PHONE_NUMBER,
ContactsContract.Contacts.DISPLAY_NAME }, null, null,
ContactsContract.Contacts.DISPLAY_NAME + " ASC");
2.Dont do the time taking process in the UI thread..Use AsyncTask instead
Note : This two steps will resolve to some extent..but not completely
I made it by reduce repeated query wich is expensive. Best of my solution is that method found all mobile phones and email for each contact and insert to list for every contact values. It is fast as storm now :)
//contact entity
public class MobileContact {
public String name;
public String contact;
public Type type;
public MobileContact(String contact, Type type) {
name = "";
this.contact = contact;
this.type = type;
}
public MobileContact(String name, String contact, Type type) {
this.name = name;
this.contact = contact;
this.type = type;
}
public enum Type {
EMAIL, PHONE
}
#Override
public String toString() {
return "MobileContact{" +
"name='" + name + '\'' +
", contact='" + contact + '\'' +
", type=" + type +
'}';
}
}
// method for collect contacts
public List<MobileContact> getAllContacts() {
log.debug("get all contacts");
List<MobileContact> mobileContacts = new ArrayList<>();
ContentResolver contentResolver = context.getContentResolver();
// add all mobiles contact
Cursor phonesCursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.CONTACT_ID}, null, null, null);
while (phonesCursor != null && phonesCursor.moveToNext()) {
String contactId = phonesCursor.getString(phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
String phoneNumber = phonesCursor.getString(phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)).replace(" ", "");
mobileContacts.add(new MobileContact(contactId, phoneNumber, MobileContact.Type.PHONE));
}
if (phonesCursor != null) {
phonesCursor.close();
}
// add all email contact
Cursor emailCursor = contentResolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, new String[]{ContactsContract.CommonDataKinds.Email.DATA, ContactsContract.CommonDataKinds.Email.CONTACT_ID}, null, null, null);
while (emailCursor != null && emailCursor.moveToNext()) {
String contactId = emailCursor.getString(emailCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.CONTACT_ID));
String email = emailCursor.getString(emailCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
mobileContacts.add(new MobileContact(contactId, email, MobileContact.Type.EMAIL));
}
if (emailCursor != null) {
emailCursor.close();
}
// get contact name map
Map<String, String> contactMap = new HashMap<>();
Cursor contactsCursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER}, null, null, ContactsContract.Contacts.DISPLAY_NAME);
while (contactsCursor != null && contactsCursor.moveToNext()) {
String contactId = contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.Contacts._ID));
String contactName = contactsCursor.getString(contactsCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
contactMap.put(contactId, contactName);
}
if (phonesCursor != null) {
phonesCursor.close();
}
// replace contactId to display name
for (MobileContact mobileContact : mobileContacts) {
String displayName = contactMap.get(mobileContact.name);
mobileContact.name = displayName != null ? displayName : "";
}
// sort list by name
Collections.sort(mobileContacts, new Comparator<MobileContact>() {
#Override
public int compare(MobileContact c1, MobileContact c2) {
return c1.name.compareTo(c2.name);
}
});
return mobileContacts;
}
The contacts in larse size use in backround task.
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number[i]));
ContentResolver contentResolver = getContentResolver();
Cursor search = contentResolver.query(uri, new String[]{ContactsContract.PhoneLookup._ID,
ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null);
try {
if (search != null && search.getCount() > 0) {
search.moveToNext();
name = search.getString(search.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
id = search.getString(search.getColumnIndex(ContactsContract.Data._ID));
System.out.println("name" + name + "id" + id);
/* tv_name.setText(name);
tv_id.setText(id);
tv_phone.setText(number);*/
}
} finally {
if (search != null) {
search.close();
}
}
Fastest way for me soo far .
ContentResolver cr = mContext.getContentResolver(); Cursor cursor= mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, PROJECTION, "HAS_PHONE_NUMBER <> 0", null, null); if (cursor!= null) { final int displayNameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); final int numberIndex = cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER); final int idIndex= cursor.getColumnIndex(ContactsContract.Contacts._ID); String displayName, number = null, idValue; while (cursor.moveToNext()) {
displayName = cursor.getString(displayNameIndex);
idValue= cursor.getString(idIndex);
Cursor phones = mContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, "contact_id = '" + idValue + "'", null, null);
phones.moveToFirst();
try {
number = phones.getString(phones.getColumnIndex("data1"));
}
catch (CursorIndexOutOfBoundsException e)
{`
}
phones.close();
userList.add(new ContactModel(displayName , number , null , }
I m making one app in which I want to have all records from my android mobile 4.0 to my android application. I have done this also. but problem is I have almost 200 contacts in my phonebook but I m getting only 90 records randomly in my application. I have tried a lot. but nothing solution I found out. can any one has solution? below is my code :
ContentResolver cr=getContentResolver();
Cursor cur=cr.query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);
if (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(Integer.parseInt(cur.getString
(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER ))) > 0)
{
//Query phone here. Covered next
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new
String[]{id}, null);
while (pCur.moveToNext())
{
// Do something with phones
String pnumber
=pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactids.add(id);
names.add(name.trim().toLowerCase());
PhoneNumbers.add(pnumber);
}
pCur.close();
}
else
{
String pnumber="";
contactids.add(id);
names.add(name);
PhoneNumbers.add(pnumber);
}
}
finally I have done with following code. But the problem with this is it can't fetch records if contacts are more then 1500. and till 1500 records process is very slow.
public class MyActivity extends Activity {
public Cursor cur;
public int j=0;
#Override
public void onCreate(Bundle savedInstanceState)
{
cur=getContacts();
startManagingCursor(cur);
cur.moveToFirst();
Button btn=(Button)findViewById(R.id.button1);
btn1.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
contactids=new ArrayList<String>();
names=new ArrayList<String>();
PhoneNumbers=new ArrayList<String>();
try
{
new showdialog1(MyActivity.this).execute();
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
});
}
class showdialog1 extends AsyncTask<Void, Void, Void>
{
public showdialog1(Activity act) {
super.onPreExecute();
}
#Override
protected void onPreExecute() {
dialog = ProgressDialog.show(MyActivity.this,"title", "message");
}
#Override
protected Void doInBackground(Void... params) {
if (cur.getCount() > 0)
{
do
{
String id = cur.getString(
cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(
cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Cursor pCur = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +"=" +id, null, null);
if(pCur.getCount()>0)
{
while (pCur.moveToNext())
{
// Do something with phones
String pnumber=pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactids.add(id);
names.add(name.trim().toLowerCase());
PhoneNumbers.add(pnumber);
}
pCur.close();
}
else
{
String pnumber="";
contactids.add(id);
names.add(name.trim().toLowerCase());
PhoneNumbers.add(pnumber);
}
}while (cur.moveToNext());
cur.close();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
dialog.dismiss();
int contactidsize=contactids.size();
int namesize=contactids.size();
int numbersize=contactids.size();
saverecords();
return;
}
}
}
you get your contact list of your phone..
try this code and after that if you want to use contact from list you select that contace and use details of that contact (ex: number, name ,email.id etc..)
plz goto below link
/*** USE this CODE ******/
int PICK_CONTACT=1;
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, PICK_CONTACT);`
You are using the condition:
Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER ))) > 0)
which does not consider the contacts that doesnot have phone numbers .
Hope this works
See ContactManager http://developer.android.com/resources/samples/ContactManager/index.html
Create and initialize boolean variable mShowInvisible - if set to true, it will list all contacts regardless of user preference
/**
* Obtains the contact list for the currently selected account.
*
* #return A cursor for for accessing the contact list.
*/
private Cursor getContacts(){
// Run query
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME
};
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '"(mShowInvisible ? "0" : "1") + "'";
String[] selectionArgs = null;
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
return managedQuery(uri, projection, selection, selectionArgs, sortOrder);
}
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...