Contact Store
Access to contacts is one of the most frequent use cases in Android applications. Even if your app is
not a contact management app, there are various cases where you might need access to the device
contacts (such as referring other users to the app).
For developers to access the device
contacts, they need to use ContentProviders. This introduces a lot of frustrations and complications. For someone that has never worked with
ContentProvider
s before, the documentation can be tedious to go through. The lack of a type-safe
API leads to repeated errors, developer frustration, along with a waste of time and resources for
the developer and the team.
Contact Store is a modern contacts Android API written in Kotlin. It utilises Coroutine’s Flow to
notify the developer for updates happening to the Contacts database.
Installation
Using Gradle:
repositories {
...
mavenCentral()
}
dependencies {
implementation 'com.alexstyl:contactstore:0.2.0'
}
How to fetch contacts using Contact Store?
The following sample returns a list of all contacts in the device. Each contact will contain an id,
a display name and whether they are starred or not:
val store = ContactStore.newInstance(application)
store.fetchContacts()
.collect { contacts ->
val contactString = contacts.joinToString(", ") {
"DisplayName = ${it.displayName}, isStarred = ${it.isStarred}, id = ${it.contactId}"
}
println("Contacts emitted: $contactString")
}
⚠️ The user must have already granted
the READ_CONTACTS
permission before collecting the flow.
If you need to query specific details about a contact (commonly used in contact detail screens), the
following sample returns a
contact’s Structured Names
and phone numbers:
val store = ContactStore.newInstance(application)
store.fetchContacts(
predicate = ContactLookup(
inContactIds = listOf(contactId)
),
columnsToFetch = listOf(
ContactColumn.NAMES,
ContactColumn.PHONES
)
)
.collect { contacts ->
val contact = contacts.firstOrNull()
if (contact == null) {
println("Contact not found")
} else {
val phones = contact.phones
val contactString = contacts.joinToString(", ") { contact ->
"Names = ${contact.firstName} ${contact.middleName} ${contact.lastName} " +
"phones = ${phones.map { "${it.value} (${it.label})" }}"
}
println("Contacts emitted: $contactString")
}
}
Always make sure to query only the columns that you need. In the case where a property is accessed
which was not queried, an Exception
is thrown.
How to edit contacts using Contact Store?
The following snippets show how to edit contacts in the device. ⚠️ The user must have already
granted
the WRITE_CONTACTS
permission before calling execute()
.
Insert a new contact
val store = ContactStore.newInstance(application)
store.execute(SaveRequest().apply {
insert(MutableContact().apply {
firstName = "Paolo"
lastName = "Melendez"
phones.add(
LabeledValue(
value = PhoneNumber("555"),
label = Label.PhoneNumberMobile
)
)
})
})
Update an existing contact
In order to update a contact, you first need to get a reference to the contact from the store. Only
the values queried will be updated. This is by design, in order to prevent accidental value
overrides.
The following code modifies a contact’s note:
val foundContacts = store.fetchContacts(
predicate = ContactLookup(inContactIds = listOf(5L)),
columnsToFetch = listOf(ContactColumn.NOTE)
).first()
if (foundContacts.isEmpty()) return // the contact was not found
val contact = foundContacts.first()
store.execute(SaveRequest().apply {
update(contact.mutableCopy().apply {
note = Note("To infinity and beyond!")
})
})
Deleting a contact
The following code shows how to delete a contact by id:
store.execute(SaveRequest().apply {
delete(contactId = 5L)
})
Getting Help
To report a specific problem or feature request, open a new issue on Github.
License
Apache 2.0. See the LICENSE file for details.
Author
Made by Alex Styl. Follow @alexstyl on Twitter for future updates.