Retrieving Android Contacts

If you are developing a social networking app, or something similar (and who isn’t!), then you might need to retrieve contacts. There are several samples out there that do something like this (sample code in MonoDroid):

private void PopulateContacts()
{
   var uri = ContactsContract.Contacts.ContentUri;
   var cursor = ManagedQuery(uri, null, null, null, null);
   while (cursor.MoveToNext())
   {
      var contactId = cursor.GetString(cursor.GetColumnIndex(BaseColumns.Id));
      txtContacts.Text += System.Environment.NewLine + "Id = " + contactId;
      txtContacts.Text += System.Environment.NewLine + "Name = " +       cursor.GetString(cursor.GetColumnIndex(ContactsContract.ContactsColumns.DisplayName));
      var emailCursor = ManagedQuery(ContactsContract.CommonDataKinds.Email.ContentUri, null, "CONTACT_ID" + " = " + contactId, null, null);
      while (emailCursor.MoveToNext())
      {
         var email = emailCursor.GetString(emailCursor.GetColumnIndex("DATA1"));
         txtContacts.Text += System.Environment.NewLine + "Email: " + email;
       }
      emailCursor.Close();
      txtContacts.Text += System.Environment.NewLine;
   }
   cursor.Close();
}


This works just fine for short contact lists, but who has those? Test machines, of course. I had a project that used this technique, and it worked great for me. The client, however, was far more popular than I, and had three times as many contacts. He crashed hard every time. The app had a pretty heavy footprint – it was doing a lot of dynamic styling and displayed a lot of images, so it wasn’t easy on memory to start with, and the contacts code threw it over the edge.
So where’s the problem? Note that the cursors are all ManagedQuery objects. ManagedQuery is theoretically handy, because it manages memory for you. Don’t try setting it to null after closing for example, because it deals with that. Unfortunately, when combined with Mono’s garbage collection, the management appears to have some issues. ManagedQuery is also deprecated, so we can ignore all of that and move on. To replace the ManagedQuery, use the CursorLoader.

private void PopulateContacts()
{
   CursorLoader clName = new CursorLoader(this);
   clName.SetProjection(null);
   clName.SortOrder = ContactsContract.ContactsColumns.DisplayName;
   clName.Uri = ContactsContract.Contacts.ContentUri;
   Android.Database.ICursor cName = (Android.Database.ICursor)clName.LoadInBackground();
   while (cName.MoveToNext())
   {
      int nameIndex = cName.GetColumnIndex(ContactsContract.ContactsColumns.DisplayName);
      string contactId = cName.GetString(cName.GetColumnIndex(BaseColumns.Id));
      string name = cName.GetString(cName.GetColumnIndex(ContactsContract.ContactsColumns.DisplayName));
      txtContacts.Text += System.Environment.NewLine + "Id = " + contactId;
      txtContacts.Text += System.Environment.NewLine + "Name = " + name;
      // Cursor loader to query contact email
      CursorLoader clEmail = new CursorLoader(this);
      clEmail.SetProjection(new String[] {     ContactsContract.CommonDataKinds.Email.Address });
      clEmail.Uri = ContactsContract.CommonDataKinds.Email.ContentUri;
      clEmail.Selection = ContactsContract.RawContactsColumns.ContactId + " = ?";
      clEmail.SetSelectionArgs(new String[] { contactId });
      // Execute queries and get results from cursors
      Android.Database.ICursor cEmail = (Android.Database.ICursor)clEmail.LoadInBackground();
      int emailIndex =     cEmail.GetColumnIndex(ContactsContract.CommonDataKinds.Email.Address);
      while (cEmail.MoveToNext())
      {
         string email = cEmail.GetString(emailIndex);
         if (!string.IsNullOrEmpty(email))
            txtContacts.Text += System.Environment.NewLine + "Email: " + email;
      }
      cEmail.Close();
   }
   cName.Close();
}

Hopefully, this can save you some frustration in debugging memory issues.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s