I'm trying to use the following code to grab a random mobile phone number from the contacts:
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, "DISPLAY_NAME = '" + "NAME" + "'", null, null);
cursor.moveToFirst();
String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
Cursor phones = cr.query(Phone.CONTENT_URI, null, Phone.CONTACT_ID + " = " + contactId, null, null);
List numbers = new ArrayList();
while (phones.moveToNext()) {
String number = phones.getString(phones.getColumnIndex(Phone.NUMBER));
int type = phones.getInt(phones.getColumnIndex(Phone.TYPE));
switch (type) {
case Phone.TYPE_MOBILE:
numbers.add(number);
break;
}
}
Random randGen = new Random();
return (String) numbers.get(randGen.nextInt(numbers.size()));
However, running this code produces a crash on line 4, with a message saying "CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0". The crash seems to be caused by the cursor.getString() method. Does anyone know where I'm going wrong? This is using the ContactsContract in Android 2.1. Eclipse gives no errors.
Thanks!
The moveToFirst() method returns a boolean. It returns true if it was able to move to the first row and false otherwise, indicating that the query returned an empty set.
When using a cursor, you should follow something like:
if (cursor.moveToFirst()) {
do {
// do some stuff
} while (cursor.moveToNext());
}
cursor.close();
Related
I am trying to get first name and last name in contact book by phone number.
Here is my code:
Uri contactUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Cursor cursor = cResolver.query(uri, null, null, null, null);
if(cursor != null && cursor.moveToFirst()) {
int idColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts._ID);
int firstNameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
int lastNameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
while (!cursor.isAfterLast()) {
long id = cursor.getLong(idColumnIndex);
contact = new MyContact();
contact.setId(id);
contact.setFirstName(cursor.getString(firstNameIndex));
contact.setLastName(cursor.getString(lastNameIndex));
}
cursor.close();
}
But firstNameIndex and lastNameIndex is always -1. What I am doing wrong ? Please help me.
PhoneLookup is a nice and quick way to get contact data by a phone number, but it returns a cursor limited to the columns mentioned in the docs.
You can see there's DISPLAY_NAME you can access, but not GIVEN_NAME, FAMILY_NAME.
GIVEN_NAME & FAMILY_NAME are fields stored in the Data table, which means you need to query that table separately to get to those fields.
So, you can just add another query using the contact ID you got from PhoneLookup (note that for each looked up phone there might be multiple contacts returned).
Here's a sample method to get first/last names from contact ID:
private void addNames(MyContact contact, long contactId) {
String[] projection = new String[] {StructuredName.GIVEN_NAME, StructuredName.FAMILY_NAME};
// filter to just StructuredName rows from the data table for the given contact
String selection = Data.CONTACT_ID + "=" + contactID + " AND " + Data.MIMETYPE + "=" + StructuredName.CONTENT_ITEM_TYPE;
Cursor cursor = getContentResolver().query(Data.CONTENT_URI, projection, selection, null, null);
if (cursor.next()) {
contact.setFirstName(cursor.getString(0));
contact.setLastName(cursor.getString(1));
}
cursor.close();
}
I have developed a program that shows a list of contacts from my phone book.
For this I use the following code:
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI,
null,
ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '1'",
null,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
if (cursor != null && cursor.getCount() > 0) {
while (cursor.moveToNext()) {
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(id));
Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id,
null,
null);
if (phones != null) {
while (phones.moveToNext()) {
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactList.add(new Contact(name, phoneNumber, id));
}
phones.close();
}
}
cursor.close();
}
adapter = new ContactAdapter(contactList, R.layout.contacts_list_item, getApplicationContext());
recyclerView.setAdapter(adapter);
Everything works, and the program displays all contacts from my phone book, but I want a certain number of contacts to be displayed. For example:
I open the program and load the first 50 contacts from the phone book, after scrolling, the next 50 contacts are loaded to the end of the list. and so on
Use below code that has limit cause. Replace your code with below
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI,
null,
ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '1' ",
null,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " COLLATE LOCALIZED ASC LIMIT 10");
It will get first 10 records. And in pull to refresh implementation, get more records on call back event of pull to refresh. Hope this will help you
I assume the reason you want this is because loading all contacts is very slow.
The reason it's very slow is because you currently have 1 query per contact, so if a user has 500 contacts, you'll need to run 500 queries.
You can reduce the number of queries to just one, then I assume you won't need the limit thing.
String[] projection = { Phone.CONTACT_ID, Phone.DISPLAY_NAME, Phone.NUMBER };
Cursor phones = getContentResolver().query(Phone.CONTENT_URI, projection, null, null, Phone.DISPLAY_NAME + " ASC");
while (phones.moveToNext()) {
String name = phones.getString(1);
String phone = phones.getString(2);
Long id = phones.getLong(0);
contactList.add(new Contact(name, phone, id));
}
phones.close();
If you want to display only one item per contact, and not per phone, you can change your contactList field to be a HashMap<Long, Contact> instead of a List, and add newly found phones to an existing Contact object if it already exists in the Map.
Something like:
Contact contact = allContacts.get(id);
if (contact == null) {
contact = new Contact(name, phone, id);
allContacts.put(id, contact);
} else {
contact.addPhone(phone); // you'll need to implement this
}
So I'm having trouble getting the phone number of a contact using its id.
This is the code I'm using to retrieve the number:
public String getNumber(){
//gets numbers by id
if (hasPhoneNumber){
ContentResolver contentResolver=context.getContentResolver();
Cursor cursor=contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
null,
ContactsContract.Contacts._ID+" = "+id,
null,
null
); //TODO : resolve empty cursor error
//contact seems to have no data available?
if (cursor.moveToFirst()){
cursor.moveToNext();
String contactId=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
Cursor phones=contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID+" = "+contactId,
null,
null);
if (phones.moveToFirst()){
while (phones.moveToNext()) {
this.number=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
}
phones.close();
} else {
test("cursor error...");
}
cursor.close();
return number;
} else {
return null;
}
}
It works with a few contacts but most show the "cursor error..." Toast (test("cursor error...") )
It's always the
Cursor cursor
that has the error.
My guess is it's empty but I know I have those contacts phone numbers saved. How do I fix this? Are there other values I have to request?
Thanks in advance!
EDIT:
this is how I retrieve ID and Name:
contactCursor=getActivity().getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[]{
ContactsContract.Contacts._ID,//0 - Long
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,//1 - String
ContactsContract.Contacts.HAS_PHONE_NUMBER,//2 - Integer
},
null,
null,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+" ASC");
EDIT 2:
I have everything in a github repository: https://github.com/nicolas-d-torres/Syncc
The first block of Code is inside app/src/main/java/gtsarandum/syncc/SynccContact
the second in app/src/main/java/gtsarandum/syncc/ContactFragment
I know this answer is a little late but hopefully it will help someone else with a similiar issue. Both of your cursor queries use the id as a string
ContactsContract.Contacts._ID+" = "+id,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID+" = "+contactId,
should be
ContactsContract.Contacts._ID + " = " + Uri.encode(id),
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ Uri.encode(contactId),
I am trying to find out if the caller id is in the contacts list. So the code I am using for that:
ContentResolver resolver = this.service.getContentResolver();
String number = PhoneLookup.NUMBER;
String[] projections = { number };
String selectionClause = number + " = ?";
String[] selectionClauseArgs = { callerId };
Cursor people = resolver.query(
ContactsContract.Contacts.CONTENT_URI, projections,
selectionClause, selectionClauseArgs, null);
return people.getCount() > 0 ? true : false;
I am giving the filtering functionality to the ContentResolver itself instead of fetching everything, iterating over them and checking one by one.
But I receive the following error for something reason (There are many codes but they are working just fine, since they are just subscribing to the telephony events in order to receive caller id when some one is calling!")
08-28 19:20:05.903: E/AndroidRuntime(737): java.lang.IllegalArgumentException: Invalid column number
I don't what is invalid. I am using right column name which is PhoneLookup.NUMBER constant. A similar question was asked here before: How to read contacts on Android 2.0 which I followed.
There's no phone numbers in this table. You should query it from another place.
Here's fast scratch (I belive there's better way to do it):
boolean hasPhoneNumber = (people.getInt(people.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0);
if (hasPhoneNumber) {
String id = people.getString(people.getColumnIndex(ContactsContract.Contacts._ID));
String num = getNumber(id);
}
public String getNumber(String id) {
String number = null;
String name = null;
Cursor pCur = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { id }, null);
if (pCur.moveToFirst()) {
number = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
name = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
}
pCur.close();
return number;
}
Can someone give me a correct example on how to load all MOBILE numbers saved on the phone into a List, Array or whatever is appropriate? All the examples I have found are either depreciated or do not work. Sorry to ask for a freebie like this but I am getting desparate, I can't find anything!
Here's what I have, it doesn't work. The Log.d doesn't happen.
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, "DISPLAY_NAME = '" + People.NAME + "'", null, null);
if (cursor.moveToFirst()){
Log.d("Number", "Cursor moved");
String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
Cursor phones = cr.query(People.CONTENT_URI, new String[]{People.NAME, People.NUMBER}, null, null, People.NAME + " ASC");
while (phones.moveToNext()) {
String number = phones.getString(phones.getColumnIndex(Phone.NUMBER));
int type = phones.getInt(phones.getColumnIndex(Phone.TYPE));
switch (type) {
case Phone.TYPE_MOBILE:
//Add to the list of numbers
Log.d("Number", number);
break;
}
}
}
Thank you!
Joel,
Cursor phones = cr.query( ContactsContract.CommonDataKind.Phone.NUMBER, .... );
And you need to compare with ContactsContract.CommonDataKind.Phone.TYPE = 2.
Thank you.