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.1.2'
}
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")
}
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. 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.