How can get data from address-book faster in Android?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Slow contact loading in Android apps is usually caused by inefficient query patterns rather than raw device speed. Many implementations fetch too many columns, run content resolver calls on the main thread, or issue repeated nested queries for each contact. Faster retrieval comes from one efficient query plan, background execution, and minimal transformation work before first render.
Start With a Lean Projection
Contacts provider exposes many fields, but list screens usually need only a few. Query only required columns and avoid heavy blobs such as photos during initial load.
Reducing projection size often gives immediate gains on large address books.
Run Queries Off the Main Thread
Content provider operations can block UI rendering. Use coroutines on Dispatchers.IO and return mapped data back to UI thread.
The use block prevents cursor leaks and keeps memory stable.
Avoid Nested Per-Contact Queries
A common slow pattern is querying contact IDs first, then querying numbers separately for each ID. That creates many provider calls and poor scaling.
Prefer querying CommonDataKinds.Phone once and deduplicating in memory if needed.
This keeps one query path and predictable runtime.
Cache, Observe, and Incrementally Refresh
If contacts are shown frequently, cache transformed rows in memory or local database. Register content observer to invalidate cache on changes.
High-level strategy:
- Load cached contacts immediately for fast first paint.
- Refresh in background from provider.
- Update cache and UI if data changed.
This gives responsive UX even when provider query is slow.
Permission and Lifecycle Handling
Contact reads require runtime permission checks. Handle permission denial quickly and avoid retry loops that block UI progress.
Also tie loading jobs to lifecycle-aware scopes such as viewModelScope. Cancel work when screen closes to avoid stale updates and unnecessary CPU usage.
Measure and Verify Performance
Track timing around query and mapping stages, not only total screen load time.
Metrics worth logging:
- query duration
- row count
- transform duration
- time to first list item rendered
Measure before and after each change. Optimization without measurement usually shifts work instead of reducing it.
Common Pitfalls
A common pitfall is selecting too many unused columns, which inflates provider work and memory pressure. Another is querying on main thread, causing jank and potential ANR errors. Nested queries per contact are also frequent and scale poorly. Teams sometimes leak cursors by skipping use or close in exception paths. Finally, many apps reload full contacts on each screen entry without caching or observer-based invalidation. If the contact list is central to the product, the loading strategy should be treated as data access design, not UI glue code.
Summary
- Use minimal projections and targeted query endpoints.
- Run contact queries on background dispatchers.
- Prefer one broad query over nested per-contact requests.
- Deduplicate in memory when UI needs one row per contact.
- Cache results and refresh on content changes.
- Profile query and mapping time to validate real improvements.

