I want to create a single Cursor that contains both given name, family name and phone nr. These columns are not located together in any of the containers available under ContactsContract and the only way I've been able to get this information is by first getting a cursor for the names and then getting phone numbers by creating a separate cursor for every contact. This solution forces me to read the data to a local data structure instead of just using an adapter on the cursor and imposes a lot of performance overhead (around ~5s with ~140 contacts with phone numbers).
Is there any way to create two cursors and then join the tables? Or is there any other way?
I have been struggling with this question for the last two days and read about everything I found on google, but really can't get anything working as I want too. This can't really be impossible, or is it?
Thanks in advance!
You can get the DISPLAY_NAME and NUMBER from ContactsContract.CommonDataKinds.Phone. Try this:
Uri uri = Phone.CONTENT_URI;
String[] projection = new String[]
{Phone.DISPLAY_NAME, Phone.NUMBER, Phone.CONTACT_ID, Phone._ID}
Cursor contactsCursor = getContentResolver().query(uri, projection, null, null, null);
Related
Is it possible to retrieve all the phone numbers with just one query(it's ok even if it's a bit slow)?
I found many topics that suggest to make query for the contact list and then a query for each contact but that's really slow.
The only solutions that I found with one query, retrieve just the main number. I need all the numbers of each contact plus the type.
Thanks.
try this
Cursor cursor = getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[] {Phone._ID, Phone.DISPLAY_NAME, Phone.NUMBER}, null, null, Phone.DISPLAY_NAME + " ASC");
I am a little bit confuse about the how to use Data.HAS_PHONE_NUMBER.
I have inserted contacts along with some additional Data and I would like to retrieve some of those contacts.
If I'm running the following code eveything is fine:
Uri uri = Data.CONTENT_URI;
String[] projection = new String[]{Data.CONTACT_ID, Data.DISPLAY_NAME };
String selection = Data.DATA4+" = ?";
String[] selectionArgs = new String[] {MY_VALUE};
Cursor truContactCursor = mContext.getContentResolver().query(uri, projection, selection, selectionArgs, null);
Now, I would like to know if those contacts have a phone number so I added HAS_PHONE_NUMBER into the projection like this:
String[] projection = new String[]{Data.CONTACT_ID, Data.DISPLAY_NAME, Data.HAS_PHONE_NUMBER };
When running the query I got the following execption:
java.lang.IllegalArgumentException: Invalid column has_phone_number
Why can I not access to HAS_PHONE_NUMBER? There is no problem with Data.DISPLAY_NAME which is in the same table. How are we suppose to use Data.HAS_PHONE_NUMBER then?
Thanks for your answer
Use HAS_PHONE_NUMBER is used for checking whether an contact has at least one phone number.example:
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if(cursor.getCount()>0){
while (cursor.moveToNext()) {
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));id
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if(cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))>0){
//Query phone here.
}
or add in projection:
String [] projection = {ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER};
Add "Data.MIMETYPE=ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE" to the selection statement.
The result cursor will include only the rows which have a phone number.
Tip.
There is the case: several numbers in one contact.
If you want all the numbers to be queried, add "ContactsContract.Data.DATA1" (Which means phone number) to the projection statement.
I encountered this same problem, and the only other reference to the problem I have found is another stackoverflow question.
I am planning on writing my own ContentProvider to do the "join" through programmatic means. That is, do the original query against the Data.CONTENT_URI but without the Data.HAS_PHONE_NUMBER projection, and then requery the given contact for the actual value of Data.HAS_PHONE_NUMBER. This surely lacks the performance of an actual DB join (being an n+1-type of select), but will provide the desired/expected functionality. This extra processing could be made conditional upon the OS level in order to maintain the efficiency on correctly functioning OS versions.
Given yulistic's answer above and my own experience, it would appear to be a bug in some versions of Android that this implicit join is not done. My Android v2.3.7 phone crashes with the same error you receive when Data.HAS_PHONE_NUMBER is in the projection, whereas my Android v4.2.2 tablet does not crash.
I have entered an Android Bug against the issue:
https://code.google.com/p/android/issues/detail?id=54095
Rob
I have been trying to get all contacts of device sorted by the order they were added.
I am using following query:
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.CONTACT_STATUS_TIMESTAMP };
Cursor c = getContentResolver().query(uri, projection, null, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_STATUS_TIMESTAMP);
It is not making any difference whether I am passing null or ContactsContract.CommonDataKinds.Phone.CONTACT_STATUS_TIMESTAMP in the sort order of the query
After inspection, the cursor has null in all timestamp columns. Is there a way to get this done or what I am doing wrong in this?
That is the timestamp for the status update for the contact. You are getting null probably because none of the contacts have status updates.
Because of how contacts are aggregated, i don't think there is a way to find out which contact was added first because a contact's ID can actually change and appear to be added later than it originally was. Why do you want to figure this information out?
I am looking to perform the following query (in pseudo-code) on Android:
SELECT C.ID, C.NAME, CASE ISNULL(G.GROUPID,0) = 0 THEN 0 ELSE 1 END INGROUP
FROM CONTACTS C
LEFT JOIN GROUPMEMBERSHIP G ON G.CONTACTID = C.ID AND G.GROUPID = ?
I am looking to select the ID and Name of ALL contacts in the system address book, via the default Contacts ContentProvider, along with a
0/1 field indicating whether the contact is a member of group ? .
I could of course get all contacts easily enough, then loop through and query the membership separately easy enough in my Adapter class, but I'd imagine performing the two queries as one outer joined query would yield much better performance.
Can I do this with the standard high-level string-projection and ContentResolver.query() method? Or would this kind of query require digging into more direct SQL execution?
Edit: Okay, so this doesn't actually solve the question asked, because eidylon is tied to an existing ContentProvider as mentioned in their question. However, this does cover how you do a JOIN if you own the ContentProvider source and API. So I'll leave it for those who want to know how to handle that case.
This is easy! But unintuitive... :)
query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
Okay, so what is URI? Typically, you have one URI per table.
content://com.example.coolapp.contacts serves data out of your CONTACTS table.
content://com.example.coolapp.groupmembers serves data out of your GROUPMEMBERSHIP table.
But URI is really just a string. Use it however you like. Make a block of code in your ContentProvider that responds to content://com.example.coolapp.contacts_in_group. Within that block of code in the ContentProvider, you can get raw access to your SQLite DB, unfettered by the limited query() data model. Feel free to use it!
Define your selection fields however you like. They don't have to map to table column names -- map them how you need to, in order to get your parameters in.
Define your projection how you need -- It may contain columns from both tables after the join.
Bing, you're done. Google does this same model internally in their own code -- Go look at the Contacts provider API -- you see "bla.RawContact" and "bla.Contact" and etc as content URIs. Each serves data out of the same table in the DB -- the different URIs just provide different views of that same table!
Nope, you can't do that kind of queries with the ContentResolver.query() method.
You will need to write something like this:
SQLiteDatabase db = YourActivity.getDbHelper().getReadableDatabase();
String query = yourLongQuery;
Cursor c = db.rawQuery(query, null);
YourActivity.startManagingCursor(c);
c.setNotificationUri(YourActivity.getContentResolver(), YourContentProvider.CONTENT_URI);
You can't do that because ContentResolver has only one query method:
query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
there's no parameter for tables or FROM clauses.
I have the following problem:
I have a RawContactID and want to get every information about this contact. I run a query like this:
String selection = ContactsContract.RawContactsEntity.RAW_CONTACT_ID +" = ?";
String[] selectionArgs = new String[]{contacts[0].get(0)};
Cursor cursor = getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, selection, selectionArgs, null);
After that I run the cursor through a lot of elseif-Statemens to distinguish betweene the different MIME-Types and read the informations. Works fine, besides that it is very much code only to read informations about one contact, but ok.
The problem is that the MIME-Type for Mobilephonenumber and Telephonenumber are the same (vnd.android.cursor.item/phone_v2)??
How can i distinguish between those to different informations?
Any hint is highly appreciated!
ContactsContract.CommonDataKinds.Phone will let you distinguish between the types. There is a long list of which TYPE_HOME and TYPE_MOBILE are just two.
The sdk reference also states
You can use all columns defined for ContactsContract.Data as well as the following aliases.