简体   繁体   中英

Retrieve contacts on Android OS

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> RefQueueWorker@org.apache.http.impl.conn.tsccm.ConnPoolByRoute@42a6b128] (Running)  
    Thread [<14> pool-3-thread-1] (Running) 
    Thread [<15> ParseCommandCache.runLoop()] (Running) 

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:

  1. Add ContactsContract.Contacts._ID to your projection array. This ID field contains the contact ID of every contact.

  2. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM