How contacts content provider in android structures its data? - android

My task is to retreive name, phone, email, company and note from all contacts on android device. I have never worked with content providers before. I read content provider documentation, tutorials, saw code samples, but I'm still not quite sure: does android stores information about name, phone, email, company and note in different tables?
So do I have to query name, phone, email, company and note separately for each contact? 5 queries per contact * number of contact = most efficient way? Or do I have alternative with fewer number of queries? Why not to store all contacts and all contact fields in the same table so that it would be possible to get all data with single SELECT query (its analog in android content providers framework)?
So my main question again: do I have to make 5 queries per contact or there is more effient way?

does android stores information about name, phone, email, company and
note in different tables?
Almost. Name is stored in Contacts.DISPLAY_NAME.
phone and emails are in Data table but to interpret column names you need to use
ContactsContract.CommonDataKinds.Phone class.
Update: The original article I referred to was removed.
Here are the relevant links:
Android documentation overall
The columns reference
If you are interested in what goes on behind the curtain, google implemented their contact database (as of 4.2) so that phone, email are stored all in the same table called data. This table has columns like data1, data2 .... data15, which allows storing diverse data in that table as long as attribute of that data item do not exceed 15.
My guess it is for performance reasons - much faster to select all the data about one contact in one query() call.
Name is another story. It is stored in two tables, "raw_contacts"(column display_name) and also "data" (column "data1")

Related

Should I rely on SOURCE_ID when reading Android Contacts?

I am creating an android contacts app, so I regularly read user's contacts and store them in my app. To do this, I need to rely on some kind of ID so that I know which contact I should update (or add/delete) in my app and Contacts Provider supplies several of them:
CONTACT_ID is the aggregate contact id,
each aggregate contact consists of one or more Raw Contacts, each with its own RAW_CONTACT_ID,
and most important, each Raw Contact has a SOURCE_ID, which is supposed to be the server id, i.e. the id this contact has in this account's server.
I 've chosen to rely on SOURCE_ID, since this sounds like the most stable one. E.g. when user removes and re-adds the same account in their device, I wouldn't want this account's contacts to get different IDs, because I wouldn't be able to match them in my app.
However, only Gmail sync adapter seems to keep the promise documented below. Exchange sync adapters unfortunately do not, SOURCE_ID changes, and it's definitely not any server id, since it has a small number like 23:4.
Question: Any ideas how to overcome this problem? Am I using the right ID for the intended use? Does exchange adapter stores the "permanent server id" in some other field?
Documentation: The SOURCE_ID must be unique for each account type and should be stable across syncs:
Unique: Each raw contact for an account must have its own source id. If you don't enforce this, you'll cause problems in the contacts
application. Notice that two raw contacts for the same account type
may have the same source id. For example, the raw contact "Thomas
Higginson" for the account emily.dickinson#gmail.com is allowed to
have the same source id as the raw contact "Thomas Higginson" for the
account emilyd#gmail.com.
Stable: Source ids are a permanent part of the online service's data for the raw contact. For example, if the user clears Contacts Storage
from the Apps settings and re-syncs, the restored raw contacts should
have the same source ids as before. If you don't enforce this,
shortcuts will stop working.
LOOKUP_KEY is what you're looking for.
LOOKUP_KEY
An opaque value that contains hints on how to find the
contact if its row id changed as a result of a sync or aggregation.
You should use a pair of <CONTACT_ID, LOOKUP_KEY> to keep track of contacts.
In normal use, use the CONTACT_ID value, but if your code gets a hint that the CONTACT_ID has changed (either missing, or unexpected contact name), you can use the LOOKUP_KEY to find the new contact-id.
Or you can use Contacts.getLookupUri() to get a URI you can always use to quickly find a contact no matter what its CONTACT_ID or LOOKUP_KEY actual values are.
First thing, it's not a good idea to store the Id in your application and hoping that the Id won't change over time and be consistent. You are right about 'SOURCE_ID' column that it's more consistent compared to the other two (CONTACT_ID is the most brittle while 'RAW_CONTACT_ID' persists at least until user logs out of an account and logs in again).
We had a syncable account with contacts and we used to keep the unique id in one of the general purpose columns in the 'raw_contacts' table (SYNC1 - SYNC10). So although Google suggests that account providers use the database columns in a certain manner but it's upto the provider totally.
General rule to follow is, never use those id's for long term persistence and if you do so, expect them to change. Also since you are making a contact App, you obviously need some kind of reference key. In such case, don't go by the rule that all account providers will put their key in the same column. It's brittle but that's the way it is.
Edit - You should use ContactsColumns.LOOKUP_KEY (previous answer also cited the same). As per the Google Documentation -
LOOKUP_KEY
Added in API level 5 String LOOKUP_KEY An opaque value that contains
hints on how to find the contact if its row id changed as a result of
a sync or aggregation.
Constant Value: "lookup"
https://developer.android.com/reference/android/provider/ContactsContract.ContactsColumns.html#LOOKUP_KEY
You can fetch the lookup key if you have the contact Id using API's provided. Look here - https://developer.android.com/reference/android/provider/ContactsContract.Contacts.html

Android Contacts: Is it possible to reference a given contact entry using a URN?

Let me try and clarify my intentions.
I'm developing an app that accesses to the Android contacts provider. I have already implemented a mechanism for pulling contacts from the contacts provider and storing the results in an SQLite table. Currently, when I query for the results of a contact's _ID, I can retrieve all the data for that contact, phone numbers, email addresses, etc.
However, in order to specify which of those my app should use on future occasions, I have to store the resulting contact data (e.g. CommonDataKinds.Phone.NUMBER, CommonDataKinds.Phone.TYPE etc) in the SQL table.
This presents a problem if the data in the Android contacts provider has changed. One solution I have considered is to re-query the _ID and store the data that has changed. However, implementing such a solution requires gathering all data for that contact, making it difficult to determine the correct contact data to use.
My question is thus:
Is there a unique record key used in the Android Provider's contact data, in the same way as there is in the Provider's contact entry itself? A phone number or email address equivalent of Contact._ID?
Failing that, does the Android contacts provider store the last modified date and time? I'm hoping that if I can't reference the contact data in the provider, I can at least run a check to see if anything has changed since the contact was selected for use in the app, allowing my app to alert the user that the data has changed.
Yoi may use ContentObserver with the help of a service to monitor for contacts change or update.
for example-
extend contentObserver-
public class Contact_change extends ContentObserver
register contentobserver-
Contact_change changeObserver = new Contact_change();
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true,chageobserver);
By using this you can monitor for contact changes and update your database.
So while looking to see what was possible, I've come across some interesting findings by doing a localised record dump to my tablet.
I incorrectly referred to the phone _ID when asking my question. It's there, but it references individual records in any given contact. This might be useful, it might be exactly what I hoped, but it might also be a dead end.
So far, I've retrieved a contact using the Android Contacts Provider, which returns the contact's data including the fields that follow
ContactsContract.Contacts._ID
ContactsContract.Contacts.DISPLAY_NAME
After assigning the _ID to a String and using it in a query, I initially searched for the _ID in the ContactsContract.Data._ID field, which did not work as intended.
That's when I realised I was doing it wrong. I needed to apply the search to ContactsContract.Data.CONTACT_ID, which then retrieved all related data records for my selected contact.
Having corrected the error and re-ran my query, I found a series of records for the CONTACT_ID, each of which had its' own unique _ID (with the exception of photos and binary data, which all had a null reference to _ID instead.
Now the question is: Does this data reference change even if a phone number, email address or IM entry is modified, as opposed to deleted and re-created? I'll probably find out through further testing, but I wanted to ask if anyone had already tried this first.
Ultimately, I am hoping my internal SQL table can store only the CONTACT_ID and the _ID for each entry, relying on callbacks to the Android Provider to pull the relevant values. That way, I can be sure the data displayed in my app is up to date between the app and the stored contact data on the device.
Combined with the change notifier code provided here, I should be able to alert the user to any changes that may require action on their part.
Update:
More investigation reveals that the UID associated with a given contact entry is preserved through entry edits.
The UID is lost obviously on deletion, and in my brief testing, I have not found UID's being recycled. This solves a referential integrity issue for me at least, as that UID won't suddenly reference another record out of nowhere.
The upshot for anyone else wanting to reference individual entries in the Contacts Provider is that it's possible, and you can store only the _ID and still retrieve individual entries in the provider.

Database to use for storing profile information

I'm making an application for android which is used to store profile information of a user( FirstName, LastName, Email, Username, Password ). It will also store profile picture of the person. You can think of applications like WhatsApp, Viber Tango. There are many more like it.
In order to store and access this information easily and efficiently, how should these information be stored? I'm thinking about storing this information in Relational Database like MySql. I will have FN,LN,Email,Username, password and link to profile picture as columns of table. One more issue I had in mind is that if a user has say 100 friends, should I create a new table per user so that all his/her friends can be separate and accessed from single table or I should run some complex SQL query so that it returns list of friends of user?
Thanks a lot
I believe you are on the right track. MySQL is a fine choice for storing the data as long as it is on a server that can be accessed by your application.
You will need 2 tables: one to store all of the users and another to map the users friends.
Your users table will be pretty straight forward as you have already laid out. The other table (could be named something like user_friends) would have a column containing the id of the friend that made the request, another column containing the id of the friend that accepted the request, and any other x amount of columns you may need to contain information about the friendship. Any record without an id for the accepted friend can be displayed as a pending request.
I would make sure that there can only be one record containing a mapping of friends to prevent duplicates as well.

Get contacts from SQL database by certain criteria on Android

How do I query all contacts matching a certain criteria on Android?
Let´s say, I want to have all contacts, which have a name, a phone number, but no profile picture.
As I understand the SQL thing, I need some kind of selection, which is passed to my query, but how would it exactly look in the example above?
I´m asking, because I´m currently running an app which first queries all contacts and after that I iterate through it and filter it, which seems much less performant then querying directly the right contacts
You are correct in the sense that contacts are stored in a SQLite database, but they are accessed via the Contacts Content Provider.
The Contacts Content Provider is organized in a three table fashion. At the bottom of the data structure lies the Data table. Here you will find all data that pertains to a specific RawContact (will discuss shortly). The Data table stores information like phone numbers, emails, addresses,etc. It does so by using MIME name value pairs defined on the mimetypes database. Up one level is the RawContacts database. Here all the information that pertains to the same account (i.e. Contact John Doe may have a twitter and Facebook account). In short, the RawContacts table keeps track of Data MIME types that pertain to the same person so there is no need to store the same information multiple times for different accounts. At the top of the data structure you have the Contacts table that groups all the information for a single person. It is basically a way of unifying all account information into one contact. Think of this contacts as you regularly would.
You should take a look at the Loader class which will allow you to perform queries on a background Thread. If you use this class once you implement the Loader callback for the Cursor, you will create a CursorLoader. One of its constructors parameter is
A typical MySQL where clause where you can specify the constraints you want to include as part of your query.
Here you would find a guide to Loaders to query a database.

How is Android contact information stored?

I'm writing a class that handles Android contact information and after some struggle, I've written a function that retrieves all information about the user's contacts, including all phone numbers, email addresses, postal addresses, etc. However, I still don't understand how this information is stored in the phone, so I'm hoping someone can give me some insight on this.
So, a user can have multiple phone numbers, multiple email addresses, etc. For contacts you have ContactsContract.Contacts.CONTENT_URI for the table containing all contacts and for phone numbers you have ContactsContract.CommonDataKinds.Phone.CONTENT_URI. But then there is also ContactsContract.RawContacts.CONTENT_URI, which is supposed to contain all the data for your contacts, I think. My assumption is that in the Contacts table, contact ID is the unique identifier for separate rows, whereas for the Phone table, phone number is the unique row identifier. If RawContacts contains all columns of the ContactsContract classes, then there would be no unique identifier for each row, since each contact might be assigned multiple phone numbers, multiple email addresses, etc. In other words, I don't understand how such a table is structured.
So my question is this: Are the various tables containing contact information--Contacts, Phone, Email, StructuredPostal, etc.--completely separate or is the information for each of those tables extracted from the larger RawContacts table? Or am I misunderstand what RawContacts is? Since the class I am writing will help move contacts from the phone contact list into a separate database, knowing this information will help me understand whether I should store the information in multiple databases or just one (similar to how I described the RawContacts database above).
The android API Guide on Contacts Provider gives a nice description of how the Contacts tables are stored (it's a bit convoluted, allowing the merge of many contacts)
picture of data hierarchy
your Q:
So my question is this: Are the various tables containing contact
information--Contacts, Phone, Email, StructuredPostal,
etc.--completely separate or is the information for each of those
tables extracted from the larger RawContacts table?
Looking over the docs again (I've not coded against these tables, only read docs), the Phone, Email... tables appear to be separate. However, the information looks to be stored in both tables, the contact and also in the RawContacts.

Categories

Resources