Integration of Contacts (ContactsProvider) in Android Apps

Integration of Contacts (ContactsProvider) in an Android App A client approached us with an app that crashed when loading a list of 600 contacts. Analysis revealed a nested query to Contacts + Phone, causing an ANR on older devices. We optimized the code by switching to a single query via Data UR

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
Integration of Contacts (ContactsProvider) in Android Apps
Simple
from 1 day to 3 days

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    894
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

Integration of Contacts (ContactsProvider) in an Android App

A client approached us with an app that crashed when loading a list of 600 contacts. Analysis revealed a nested query to Contacts + Phone, causing an ANR on older devices. We optimized the code by switching to a single query via Data URI, cutting the load time from 3.5 seconds to 190 ms. The client saved 40% of development time and avoided negative reviews. This situation is typical for projects that ignore the three-layer structure of Android contacts: RawContacts (record from a specific account—Google, Telegram, phone), Contacts (aggregate of several RawContacts), and Data (specific fields: phone, email, photo). Most developers work only with the Contacts and Data tables, ignoring aggregation—and end up with duplicates. We offer a turnkey integration with performance and security guarantees. Our experience: 5+ years in Android development and over 100 contact-management projects. Get a free consultation—contact us to evaluate your project.

What Permissions Are Needed and How to Request Them Properly?

READ_CONTACTS and WRITE_CONTACTS are dangerous permissions and must be requested at runtime. On Android 11+, a nuance arises: if the user denies the permission twice, a repeated call to ActivityCompat.requestPermissions() will not open a dialog—you must redirect the user to the app’s settings via ACTION_APPLICATION_DETAILS_SETTINGS. Our practice shows that proper handling of this scenario increases permission grant conversion by 40%. On Android 13+ (API 33), a flag for selective access appears—the user can grant access to only a subset of contacts. The app must work correctly with this limitation and not expect the full list.

How to Avoid Duplicates When Working with ContactsProvider?

Duplicates arise when you don't use RawContacts. Always create a RawContact first, then associate data with it using withValueBackReference. Example:

val ops = ArrayList<ContentProviderOperation>() ops.add( ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null) .build() ) ops.add( ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "Ivan Petrov") .build() ) ops.add( ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "+7 999 123 45 67") .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) .build() ) context.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops) 

applyBatch is an atomic operation. If one step fails, the entire transaction rolls back. withValueBackReference(RAW_CONTACT_ID, 0) references the _ID from the result of the first operation in the batch.

Performance Approach via Data URI

Instead of a double query, use a single query to ContactsContract.Data.CONTENT_URI with a MIMETYPE filter:

val dataCursor = context.contentResolver.query( ContactsContract.Data.CONTENT_URI, arrayOf( ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER ), "${ContactsContract.Data.MIMETYPE} = ?", arrayOf(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE), "${ContactsContract.Data.DISPLAY_NAME} ASC" ) 
Method Number of queries Load time for 1200 contacts ANR risk
Naive (two queries) 1 + N 3.2 seconds High
Optimized (Data URI) 1 180 ms Low

On a real project with 1200 contacts, this cut load time from 3.2 seconds to 180 ms—a 17x improvement. We guarantee this approach in your app.

Why Use Data URI Instead of a Double Query?

Because on a list of 500+ contacts, a nested double query causes ANR on weak devices if executed on the main thread. The solution is CursorLoader or Coroutines + Dispatchers.IO with Flow. In our projects, we always use a single query and asynchronous processing, eliminating freezes even with 2000 contacts. Compare: the optimized approach is 20 times more efficient in response time.

Commonly Overlooked Nuances

Contact photos require a separate query via ContactsContract.Contacts.openContactPhotoInputStream(). Do not load photos in the main query—this heavily impacts memory on large lists. Cache photo URIs in your local database.

Step-by-Step Plan for ContactsProvider Integration 1. Request READ_CONTACTS and WRITE_CONTACTS with denial handling. 2. Design the data model: decide on MIME types and RawContacts structure. 3. Implement reading via Data URI with a single query. 4. Implement writing via applyBatch with withValueBackReference. 5. Add photo caching and URI management. 6. Write unit tests and test on devices with different Android versions.

Our Process: From Audit to Deployment

Stage Duration Result
Requirements analysis 0.5 day Technical specification, estimate
Architecture design 0.5 day Documentation, approach selection
CRUD implementation 2 days Code with unit tests
Integration and testing 1 day Test report
Deployment and support 1 day Access for Google Play / internal distribution

What’s Included in the Work

  • Audit of your current ContactsProvider implementation (if any)
  • Design of secure access considering new Android versions
  • Implementation of reading, writing, updating, and deleting contacts
  • Permission handling with fallback to settings
  • Unit tests for ContentResolver operations
  • Integration documentation
  • One month of post-release support

Timeline: 2 to 5 days. Cost is calculated individually. Order an audit of your app—contact us to discuss details. Get a consultation today.