Reputation: 1078
I tried to use this code snippet to retrieve one contact after another.
Info: I have set the permission <uses-permission android:name="android.permission.READ_CONTACTS"/>
Context context = getActivity();
Cursor cursor = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, new String[]{Phone.NUMBER}, null, null, null);
while (cursor.moveToNext()) {
String number = cursor.getString(cursor.getColumnIndex(Phone.NUMBER));
Log.i("Number: ", number);
}
cursor.close();
This is what my StackTrace gives out, I dont really understand what it says:
Pick [Android Application]
<terminated>Pick [Android Application]
<disconnected>DalvikVM [localhost:8600]
Pick [Android Application]
DalvikVM [localhost:8600]
Thread [<1> main] (Suspended (exception IllegalArgumentException))
<VM does not provide monitor information>
ContextImpl$ApplicationContentResolver(ContentResolver).query(Uri, String[], String, String[], String, CancellationSignal) line: 458
ContextImpl$ApplicationContentResolver(ContentResolver).query(Uri, String[], String, String[], String) line: 360
FragmentContacts.onCreateView(LayoutInflater, ViewGroup, Bundle) line: 21
FragmentContacts(Fragment).performCreateView(LayoutInflater, ViewGroup, Bundle) line: 1500
FragmentManagerImpl.moveToState(Fragment, int, int, int, boolean) line: 927
FragmentManagerImpl.moveToState(int, int, int, boolean) line: 1104
BackStackRecord.run() line: 682
FragmentManagerImpl.execPendingActions() line: 1467
FragmentManagerImpl$1.run() line: 440
Handler.handleCallback(Message) line: 730
FragmentActivity$1(Handler).dispatchMessage(Message) line: 92
Looper.loop() line: 137
ActivityThread.main(String[]) line: 5419
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]
Method.invoke(Object, Object...) line: 525
ZygoteInit$MethodAndArgsCaller.run() line: 1187
ZygoteInit.main(String[]) line: 1003
NativeStart.main(String[]) line: not available [native method]
Thread [<10> Binder_2] (Running)
Thread [<9> Binder_1] (Running)
Daemon Thread [<11> [email protected]@42a6b128] (Running)
Thread [<14> pool-3-thread-1] (Running)
Thread [<15> ParseCommandCache.runLoop()] (Running)
Upvotes: 1
Views: 128
Reputation: 3086
That is because you are trying to fetch a column's data that you did not request while querying. Change your query line to this:
Cursor cursor = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, new String[]{Phone.NUMBER}, null, null, null);
For every column you want to read data from, make sure you're also including it in your projection array. The 2nd parameter of query() method is a String array containing the columns you're interested in.
A better approach would be this:
// columns we're interested in reading data from
String[] projection = {Phone.NUMBER, OTHER_COLUMNS};
Cursor cursor = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, projection, null, null, null);
Read this tutorial to get more information: http://developer.android.com/training/load-data-background/index.html
Update: You cannot directly fetch phone numbers from the contacts table. They are stored in a different table because contacts can have multiple numbers.
For this, we'll have to use nested cursor queries. Here's how it's going to work:
Add ContactsContract.Contacts._ID
to your projection array. This ID field contains the contact ID of every contact.
Iterate over your cursor and for each contact ID, fetch his numbers.
And here's the detailed solution:
// uri for the contacts data
Uri contactsUri = ContactsContract.Contacts.CONTENT_URI;
// columns we're interested in
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
};
// we do not want contacts who do not have phone numbers
// so we'll only query contacts whose phone numbers count is > 0
String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " >? ";
String[] selectionArgs = new String[] {"0"};
// query all contacts
Cursor cursor = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, projection, selection, selectionArgs, null);
// this list will hold lists of phone numbers of all contacts
ArrayList<ArrayList<String>> allContactNumbers = new ArrayList<ArrayList<String>>();
if(cursor != null){
try{
// for each contact Id, we'll fetch his numbers
while(cursor.moveToNext()){
// get his contactId
String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))
// ArrayList that will hold his phone numbers
ArrayList<String> phoneNumbers = new ArrayList<String>();
Cursor numberCursor = contResv.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new String[]{ contactId }, null);
try{
// add each phone number to phoneNumbers
while (numberCursor.moveToNext()){
String contactNumber = numberCursor.getString(numberCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneNumbers.add(contactNumber);
}
}finally{
numberCursor.close();
}
// and add each contact's phone numbers to our master list
allContactNumbers.add(phoneNumbers);
}finally{
// close the cursor when we're done using it to avoid any database leaks
cursor.close();
}
}
// now do whatever you want with allContactNumbers.
Upvotes: 2