Основы Contacts API в Android
Интерфейс работы с контактами изменился начиная с 5-ой версии API Android SDK : провайдер Contacts и все его составляющие получили статус @Deprecated. Теперь за работу с контактами отвечает провайдер ContactsContract, который внёс изменения в структуру хранения контактов, более адаптированную для Android устройств, позволяющую хранить контакты из разных источников и предоставлять их пользователю как единую сущность. В настоящее время объект описания контакта на мобильном устройстве включает не только имя и номер телефона, но и Email, Twitter, Facebook и т.д. Новый ContactsContract API позволяет системе агрегировать похожие контакты и выдавать их пользователю в одной записи, а также связывать контакт с разного рода данными.
Пользовательские данные хранятся в центральном репозитории устройства, которым управляет поставщик контактов — эффективный и гибкий компонент Android. Поставщик контактов — это источник данных, которые отображаются в приложении «Контакты» на Вашем устройстве.
Структура поставщика контактов
Поставщик контактов содержит в себе три типа данных о пользователе, как это представлено на рисунке. Каждый тип данных хранится в отдельной таблице :
В качестве наименований таблиц обычно используются названия соответствующих классов-контрактов ContactsContract. Эти классы определяют константы для URI контента, названий столбцов и значений в столбцах этих таблиц :
ContactsContract.Contacts
Строки в таблице Contacts содержат данные о пользователях, полученные путем агрегации строк необработанных контактов.
ContactsContract.RawContacts
Строки в таблице RawContacts содержат сводные данные о пользователях, относящиеся к пользовательским учетным записям и их типам.
ContactsContract.Data
Строки в таблице Data содержат сведения о необработанных контактах, например email или номера телефонов.
Имеются и другие таблицы, представленные классами-контрактами ContactsContract и представляющие собой вспомогательные таблицы. Эти таблицы поставщик контактов использует для управления своими операциями и поддержки определенных функций, имеющихся в приложении устройства «Контакты» или приложениях для телефонной связи.
Разрешения на доступ к поставщику контактов
Приложения, которым требуется доступ к поставщику контактов для чтения или записи, должны определить разрешения в файле манифеста приложения :
Профиль пользователя
Разрешения на доступ к данным поставщика контактов не распространяются на работу с профилями пользователя.
Примечание : данные о контактах пользователя являются личными и конфиденциальными. Владельцы мобильных устройств заботятся о своей конфиденциальности и часто не проявляют желания предоставлять приложениям возможности сбора данных о них самих и/или их контактах. Если владельцам не до конца ясно, для чего требуется предоставить приложению разрешение на доступ к данным контактов, они могут присвоить Вашему приложению низкий рейтинг, или вообще откажутся его устанавливать.
Строка контактов профиля связана со строкой необработанных контактов в каждой из систем, в которой используется профиль. В каждой строке необработанного контакта профиля может содержаться несколько строк данных. Константы для доступа к профилю пользователя представлены в классе ContactsContract.Profile.
Для доступа к профилю пользователя требуются отдельные разрешения. Наряду с разрешениями READ_CONTACTS и WRITE_CONTACTS (чтение и запись контакта) для доступа к профилю пользователя необходимы разрешения android.Manifest.permission#READ_PROFILE и android.Manifest.permission#WRITE_PROFILE на чтение и запись соответственно.
Помните, что профиль пользователя представляет собой конфиденциальную информацию. При запросе доступа к личной информации на устройстве пользователя обязательно укажите, для чего вам требуется доступ к профилю пользователя.
Примечание : если при получении нескольких строк контактов необходимо определить, какая из них является профилем пользователя, анализируйте значение столбца IS_USER_PROFILE этой строки. Для профиля пользователя значение должно быть «1».
Пример чтения контактов
Рассмотрим простой пример чтения списка контактов и вывода их в журнал Log. Ниже представлен листинг метода onCreate главного модуля приложения MainActivity.
Перед выполнением запроса проверим, имеются ли у нас необходимые разрешения на доступ к контактам. Для этого используем метод ContextCompat.checkSelfPermission, которому в качестве параметров передадим контекст модуля и идентификатор разрешений списка контактов. Если приложение имеет разрешения (permission), то метод вернет значение PERMISSION_GRANTED, в противном случае PERMISSION_DENIED.
При наличии необходимых разрешений вызываем метод чтения контактов readContacts, представленный ниже. В противном случае запросим необходимые разрешения методом ActivityCompat.requestPermissions, которому в качестве параметров необходимо передать контекст модуля, список запрашиваемых разрешений и «определенную в модуле константу» (PERMISSIONS_REQUEST_READ_CONTACTS).
Примечание : при запросе приложением «разрешения» методом requestPermissions(), система открывает стандартное диалоговое окно подтверждения доступа. Приложение не может изменить интерфейс диалогового окна. Если имеется необходимость представить пользователю дополнительную информацию, то это желательно сделать перед открытием окна запроса подтверждения. После запроса первого подтверждения и получения положительного ответа система запоминает результат ответа и больше не открывает окно подтверждения доступа.
Результат выполнения запроса на получение разрешений система возвращает вызовом callback метода onRequestPermissionsResult, листинг которого представлен ниже.
Листинг callback метода запроса разрешений
Система вызывает callback метод onRequestPermissionsResult при запросе разрешений методом requestPermissions. В качестве параметров методу передается массив запрошенных permissions и массив разрешений grantResults.
В примере проверяем результат полученного от системы ответа. При наличии необходимых разрешений вызывается метод readContacts.
Листинг метода чтения контактов
Метод чтения контактов readContacts в качестве параметра получает контекст приложения, используемый для вызова метода getContentResolver().query и получения результата в виде курсора. Если курсор содержит список контактов, то метод в цикле перебирает этот список и выводит в Log параметры контактов (id, name, phone). Метод можно доработать, чтобы он возвращал список контактов в виде List .
Листинг класса Contact
Класс описания контакта, используемого в методе чтения контактов устройства.
Источник
View all contacts android
Looking for the easiest way to get full-access to the breadth of Contacts in Android without having to deal with the Contacts Provider and cursors? Well, look no further =)
Whether you just need to get all or some Contacts for a small part of your app (written in Kotlin or Java), or you are looking to create your own full-fledged Contacts app with the same capabilities as the native Android Contacts app, this library has you covered!
Documentation and how-to guides are all available and linked in the repository. You can browse the Howto pages or visit the GitHub Pages. Both contain the same info but the GitHub pages are not guaranteed to be up-to-date. The GitHub wiki hosts the project roadmap. It contains all planned work and release schedules, which are organized using issues, milestones, and projects.
You can also learn more about this library through the articles I wrote about it =)
Note: This repo was open-sourced on October 4, 2021. It was private prior to that.
All features below are links to howto pages. Click on each of them to learn more!
The core library supports;
- All of the kinds of Data in the Contacts Provider; address, email, event, group membership, IM, name, nickname, note, organization, phone, photo, relation, SIP address, and website.
- Custom data integration.
- Broad queries and advanced queries of Contacts and RawContacts from zero or more Accounts. Include only desired fields in the results (e.g. name and phone number) to conserve CPU and memory. Specify matching criteria in an SQL WHERE clause fashion using Kotlin infix functions. Order by contact table columns. Limit and offset functions.
- Insert one or more RawContacts with an associated Account, causing automatic insertion of a new Contact subject to automatic aggregation by the Contacts Provider.
- Update one or more Contacts, RawContacts, and Data.
- Delete one or more Contacts, RawContacts, and Data.
- Query, insert, update, and delete Profile (device owner) Contact, RawContact, and Data.
- Query, insert, update, and delete Groups per Account.
- Query, insertupdate, and delete specific kinds of Data.
- Query, insert, update, and delete custom Data.
- Query for Accounts in the system or RawContacts table.
- Query for just RawContacts.
- Associate local RawContacts (no Account) to an Account.
- Join/merge/link and separate/unmerge/unlink two or more Contacts.
- Get and set Contact and RawContact Options. starred (favorite), custom ringtone, send to voicemail.
- Get, set, and remove Contacts/RawContact photo and thumbnail.
- Get, set, and clear default (primary) Contact Data (e.g. default/primary phone number, email, etc).
- Miscellaneous convenience functions.
- Contact data is synced automatically across devices.
There are also extensions that add functionality to every core function;
Also included are some pre-baked goodies to be used as is or just for reference;
There are also more features that are on the way!
First, include JitPack in the repositories list,
To import all modules,
To import specific modules,
Notice that when importing specific modules/subprojects, the first «:» comes after «contacts-android».
SNAPSHOTs of branches are also available,
This library is a multi-module project published with JitPack;
To retrieve all contacts containing all available contact data,
To simply search for Contacts, yielding the exact same results as the native Contacts app,
Note that for queries, you will need to add the android.permission.READ_CONTACTS permission to your app’s AndroidManifest. Additionally, the user will have to have given your app that permission at runtime (starting with Android Marshmallow). Without permissions being granted, query functions will return empty results. To make permission handling much easier, Kotlin coroutine extensions are available in the permissions module.
That’s it! BUT, THAT IS BORING! Let’s take a look at something more advanced…
To retrieve the first 5 contacts (including only the contact id, display name, and phone numbers in the results) ordered by display name in descending order, matching ALL of these rules;
- a first name starting with «leo»
- has emails from gmail or hotmail
- lives in the US
- has been born prior to making this query
- is favorited (starred)
- has a nickname of «DarEdEvil» (case sensitive)
- works for Facebook
- has a note
- belongs to the account of «john.doe@gmail.com» or «john.doe@myspace.com»
Imagine what this would look like if you use ContactsContract directly. Now, you don’t have to! The above snippet is in Kotlin but, like I mentioned, all of the core APIs are usable in Java too (though it won’t look as pretty).
Once you have the contacts, you now have access to all of their data!
Each Contact may have more than one of the following data if the Contact is made up of 2 or more RawContacts; name, nickname, note, organization, sip address.
There is no setup required. It’s up to you how you want to create and retain instances of the contacts.core.Contacts(context) API. For more info, read How do I setup the Contacts API?
More than enough APIs that will allow you to build your own contacts app!
This library is capable of doing more than just querying contacts. Actually, you can build your own full-fledged contacts app with it!
Let’s take a look at a few other APIs this library provides.
To get the first 20 gmail emails ordered by email address in descending order,
It’s not just for emails. It’s for all data kinds (including custom data).
To CREATE/INSERT a contact with a name of «John Doe» who works at Amazon with a work email of «john.doe@amazon.com» (in Kotlin),
Or alternatively, in a more Kotlinized style,
If John Doe switches jobs and heads over to Microsoft, we can UPDATE his data,
If we no longer like John Doe, we can DELETE him from our life,
Note that for insert, update, and delete functions, you will need to add the android.permission.WRITE_CONTACTS and android.permission.GET_ACCOUNTS permissions to your app’s AndroidManifest. Additionally, the user will have to have given your app that permission at runtime (starting with Android Marshmallow). Without permissions being granted, these functions will do nothing and return a failed result. To make permission handling much easier, Kotlin coroutine extensions are available in the permissions module.
Threading and permissions
This library provides Kotlin coroutine extensions in the permissions module for all API functions to handle permissions and async module for executing work in background threads.
So, if we call the above function and we don’t yet have permission. The user will be prompted to give the appropriate permissions before the query proceeds. Then, the work is done in the coroutine context of choice (default is Dispatchers.IO). If the user does not give permission, the query will return no results.
Extensions for Kotlin Flow and RxJava are also in the v1 roadmap, which includes APIs for listening to Contacts database changes.
Full in-code documentation and Howto guides and samples
The above examples barely scratches the surface of what this library provides. For more in-depth Howtos, visit the howto directory. For a sample app reference, take a look at and run the sample module.
All APIs in the library are optimized!
Some other APIs or util functions out there typically perform one internal database query per contact returned. They do this to fetch the data per contact. This means that if there are 1,000 matching contacts, then an extra 1,000 internal database queries are performed! This is not cool!
To address this issue, the query APIs provided in the Contacts, Reborn library, perform only at least two and at most six or seven internal database queries no matter how many contacts are matched! Even if there are 100,000 contacts matched, the library will only perform two to seven internal database queries (depending on your query parameters).
Of course, if you don’t want to fetch all hundreds of thousands of contacts, the query APIs support pagination with limit and offset functions 😎
Cancellations are also supported! To cancel a query amid execution,
The find function optionally takes in a function that, if it returns true, will cancel query processing as soon as possible. The function is called numerous times during query processing to check if processing should stop or continue. This gives you the option to cancel the query.
This is useful when used in multi-threaded environments. One scenario where this would be frequently used is when performing queries as the user types a search text. You are able to cancel the current query when the user enters new text.
For example, to automatically cancel the query inside a Kotlin coroutine when the coroutine is cancelled,
All core APIs are framework-agnostic and works well with Java and Kotlin
The API does not and will not force you to use any frameworks (e.g. RxJava or Coroutines/Flow)! All core functions of the API live in the core module, which you can import to your project all by itself. Don’t believe me? Take a look at the dependencies in the core/build.gradle 😀
So, feel free to use the core API however you want with whatever libraries or frameworks you want, such as Reactive, Coroutines/Flow, AsyncTask (hope not), WorkManager, and whatever permissions handling APIs you want to use.
All other modules in this library are optional and are just there for your convenience or for reference.
I also made sure that all core functions and entities are interoperable with Java. So, if you were wondering why I’m using a semi-builder pattern instead of using named arguments with default values, that is why. I’ve also made some other intentional decisions about API design to ensure the best possible experience for both Kotlin and Java consumers without sacrificing Kotlin language standards. It is Kotlin-first, Java-second (with love and care).
Modules other than the core module are not guaranteed to be compatible with Java.
If you use Proguard and the async and/or permissions , you may need to add rules for Coroutines.
This is a newly open sourced library with only one contributor so far (me). Don’t expect much support in the beginning. I am only able to work on this (and respond to issues) outside of work hours. This means late nights, weekends, and maybe holidays.
As time passes, hopefully this library gets more and more contributors. At some point, I hope to gain contributors that have become experts on this library to help me support the community by maintaining it and making admin-level decisions.
In any case, create issues for any bugs found and I’ll get to it when I get the chance depending on severity of the issue.
About
Android Contacts API Library written in Kotlin with Java interoperability. No more ContentProviders and cursors. Say goodbye to ContactsContract. Build your own contacts app!
Источник