📜 ⬆️ ⬇️

The basics of the Contacts API in Android

Most recently, I needed to make an application that needed support for working with user contacts at a basic level and, like probably any new Android developer, I arrived in a small stupor after studying the new Contacts API superficially. While working, I found very little information on this topic (except for the documentation itself, of course), and in Russian, it seemed to me, it was completely absent. That's why I decided to write this article and share my experience with others. In it, I will try to cover only the basics of working with contacts in Android, without affecting the deeper issues and synchronization issues that I deserve a separate article.

Introduction


Starting with version 5 of the Android SDK API, the interface for working with contacts has changed, and the main content provider Contacts and all its components have been given the black mark @Deprecated. Now ContactsPontract provider is responsible for working with contacts. These changes are associated with changes in the storage structure of contacts, more adapted for Android devices that need to store contacts from many different sources and present them to the user as a single entity. After all, today, a certain contact on our mobile device is not only the name and phone number, we may want to save an eMail, Im, Twitter, Facebook account of a certain person, and at the same time, we don’t want us to have a million incomprehensible entries. Therefore, the new Contacts API allows Android to aggregate similar contacts and present them to the user in one record, as well as associate a contact with various kinds of data.

Data structure


On the device, the main information about contacts is stored in three tables, in fact there are more of them there, but we will look at the main three: contacts, raw_contacts and data . To make it more clear, I sketched a simple diagram in Dia.

The contacts table stores aggregated contacts, each entry in this table represents a user contact (single entity) —the union of one or more raw (raw) contacts from the raw_contacts table. As can be seen in the diagram, the relationship between these tables is one-to-many (1-N). One entry in the raw_contacts table is the so-called raw contact. A raw contact, in Android, means a specific set of data for a particular contact. But the main data itself is not stored in this table, it is stored in the data table, and the relationship between raw_contacts and data is also one-to-many. The data table stores data directly. And each row of this table is a data set of a certain type for a contact. What type of data is stored in a row is determined by the mimetype_id column, which contains the id data types defined in the mimetype table (for example, vnd.android.cursor.item / name, vnd.android.cursor.item / photo). Now let's look at everything in more detail and with examples.
')

We work with contacts


Well, let's say we want to add a contact (Robert Smith, mobile phone. 11-22-33), how do we do this? Obviously, we ourselves cannot add a contact to the contacts table, since the system itself generates this table by aggregating similar raw_contacts . Identity of contacts is defined by the system mainly by name (identical names, surnames, etc.), but also by other criteria, which ones and how they can be managed can be viewed in the documentation . That is, if we add the raw_contact of our Robert (Robert Smith) and associate it with the data type vnd.cursor.android.item / phone, and then we will have a “similar” for the system, Robert Smith is associated with the data type vnd.cursor .android.item / email and one more with data like vnd.cursor.android.item / photo, then we will have one Robert Smith in contacts with a photo, mobile and email.

Now we will try to transfer it to the code. For the tables and their fields, as I said, the ContactsContract class and its internal classes and interfaces are responsible. For example, the interface to the raw_contacts table is the ContactsContract.RawContacts class, and for the data table, the ContactsContract.Data class. Be careful when learning their constants — interfaces to columns — pay attention to the read / write and read only labels.

From the above it follows that to begin with, we have to add a raw contact, and then associate it with the data. You can add an empty contact like this:

import android.provider.ContactsContract; Uri rawContactUri = getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, new ContentValues()); 


In contacts you should have an empty (Unknown) contact that is not related to anything. Add him a name. To do this, we need to associate our new contact with new data using its id, which can be obtained from the past query. The main interfaces to the fields of the data table are contained in the ContactsContract.CommonDataKinds container class and its internal classes and interfaces. For example, now we need
class ContactsContract.CommonDataKinds.StrucruredName containing the constants we need to add a name, as well as a MIME type constant with which we mark our field in the data table.

 /*  id   */ long rawContactId = ContentUris.parseId(rawContactUri); ContentValues values = new ContentValues(); /*      */ values.put(Data.RAW_CONTACT_ID, rawContactId); /*  MIMETYPE    */ values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); /*     */ values.put(StructuredName.DISPLAY_NAME, "Robert Smith"); getContentResolver().insert(Data.CONTENT_URI, values); 


If we add a contact in this way, we will have Robert Smith in our contact list. Now we go further, we will add to our contact also a telephone. To do this, we need the ContactsContract.CommonDataKinds.Phone class, which is an interface to the phone number data.

 values.clear(); values.put(Data.RAW_CONTACT_ID, rawContactId); /*   –   */ values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); /*   */ values.put(Phone.NUMBER, "11-22-33"); /*  –  */ values.put(Phone.TYPE, Phone.TYPE_MOBILE); getContentResolver().insert(Data.CONTENT_URI, values); 


Now in contacts we have Robert Smith who can call. But here it is expensive and expensive to add contact and data to it, in several requests. Therefore, there is a class ContentProviderOperation , which allows you to build a request that will perform all our operations in a single transaction. That they are recommended to use. This is how you can add our Robert using ContentProviderOperation .

 ArrayList<ContentProviderOperation> op = new ArrayList<ContentProviderOperation>(); /*    */ op.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) .withValue(RawContacts.ACCOUNT_TYPE, null) .withValue(RawContacts.ACCOUNT_NAME, null) .build()); /*    */ op.add(ContentProviderOperation.newInsert(Data.CONTENT_URI) .withValueBackReference(Data.RAW_CONTACT_ID, 0) .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) .withValue(StructuredName.DISPLAY_NAME, "Robert Smith") .build()); /*    */ op.add(ContentProviderOperation.newInsert(Data.CONTENT_URI) .withValueBackReference(Data.RAW_CONTACT_ID, 0) .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE) .withValue(Phone.NUMBER, "11-22-33") .withValue(Phone.TYPE, Phone.TYPE_MOBILE) .build()); try { getContentResolver().applyBatch(ContactsContract.AUTHORITY, op); } catch (Exception e) { Log.e("Exception: ", e.getMessage()); } 


This is the way to add contacts to Android. Be careful when using ContentProviderOperation , since a too large request can take a long time to complete. In general, it is better to perform all operations in a separate stream, because, for example, a user may have a weak phone and many contacts.

Otherwise, all other operations are performed in the usual way, using the providers you need, with some reservations. For example, deleting a contact from the contacts table will remove all the raw_contacts associated with it, etc.

So you can try to find our Robert in contacts:

 Cursor c = getContentResolver().query( Contacts.CONTENT_URI, new String[] {Contacts._ID}, Contacts.DISPLAY_NAME + " = 'Robert Smith'", null, null); if(c.getCount() > 0) { /*  */ } else { /*   */ } 


At this point I would like to complete the article, yet it was only basic information about the Contacts API in Andoid. I hope I managed to describe the basic principles here, and all the specifics depend on what you need to do in the process. You can simply follow these principles and find in the official documentation the interfaces you need to work. Successes!

Source: https://habr.com/ru/post/130148/


All Articles