How can we fetch displayname and organization.data through ContactsContract APIs using impicit joins so that I can both these values in a single cursor?
You can use this code to get the organization name and display name:
Cursor organizationNameCursor = cr.query(ContactsContract.Data.CONTENT_URI,new String[] {Organization.TITLE,Organization.DISPLAY_NAME}, ContactsContract.Data.CONTACT_ID + " = " + contactId + " AND ContactsContract.Data.MIMETYPE = '"
+ ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE
+ "'",null,null);
organizationNameCursor.moveToNext();
organizationName.setText(organizationNameCursor.getString(organizationNameCursor.getColumnIndex(Organization.TITLE))+" "+organizationNameCursor.getString(organizationNameCursor.getColumnIndex(Organization.DISPLAY_NAME)));
The ContactsContact data can only be fetched by using content providers which does not allow us to have explicit joins in the query.
You can however have both the values using a single query on Data database as follows:
Cursor c = getContentResolver().query(Data.CONTENT_URI,new String[] {StructuredName.DISPLAY_NAME,Organization.COMPANY}, Data..CONTACT_ID + " = " + contactId,null,null)
In that case you wont be able to get the values directly.
You can very well fetch all the details using a single query by adding a parameter
Data.MIMETYPE IN (StructuredName,CONTENT_ITEM_TYPE, Organization.CONTENT_ITEM_TYPE)
however you need to have that logic in your code which would reorder your data.
Each MIMETYPE will fetch a separate record.
Similarly you can use RawContactsEntity for the same. It provides a join between Contacts and Data database internally.
Related
I reference this link android developer training to implement for the retrieving contact detail with selection criteria
/*
* Defines the selection clause. Search for a lookup key
* and the Email MIME type
*/
private static final String SELECTION =
Data.LOOKUP_KEY + " = ?" +
" AND " +
Data.MIMETYPE + " = " +
"'" + Email.CONTENT_ITEM_TYPE + "'";
#Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
// Choose the proper action
switch (loaderId) {
case DETAILS_QUERY_ID:
// Assigns the selection parameter
mSelectionArgs[0] = mLookupKey;
// Starts the query
CursorLoader mLoader =
new CursorLoader(
getActivity(),
Data.CONTENT_URI,
PROJECTION,
SELECTION,
mSelectionArgs,
SORT_ORDER
);
...
}
When goes into change the contact name for example. Then in one case when adding contact is made by our application, cursor loader can't correctly detect the changes. I check the lookup key, that added contact key is different with others (for example : Orod-1340xxxxxxxx).
After searching the discussion, lookup key may change and suggest to use contact lookup uri with the lookup key. But the lookup uri cannot be used in above query. I need to query in Data table for the detail info.
How can i achieve that?
Thanks a lot.
Try using CONTACT_ID instead of LOOKUP_KEY.
private static final String SELECTION =
Data.CONTACT_ID + " = ? AND " +
Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
You might stumble upon warnings not to use contact-ids and instead use lookup keys or lookup uris, but that's for persisting a contact reference into a database for long keeping, if you're app is currently up and running, and just recently queried for this contact-id, it's perfectly safe and ok to use it, it's even better to use contact-ids for this purpose since it's more stable as a standalone id.
See more info here and here
I've searched the internet for this problem but couldn't get any working response.
I believe it's from the selection but I don't know what is wrong with it.
I get this error :
android.database.sqlite.SQLiteException: no such column: data1 (Sqlite code 1): , while compiling: SELECT sort_key, photo_uri ...
after executing this code to retrieve the phone contacts:
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String no07 = "%07";
String no407 = "%+407";
String selection = "((" + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY + " NOTNULL) AND ("
+ ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY + " != '' ) AND (("
+ ContactsContract.CommonDataKinds.Phone.NUMBER + " LIKE '" + no07 + "' ) OR ("
+ ContactsContract.CommonDataKinds.Phone.NUMBER + " LIKE '" + no407 + "' )))";
Cursor phones = getActivity()
.getContentResolver()
.query(uri, null, selection, null, null);
I would appreciate any help.
According to your error there is no such a column data1 from the URI you are querying. The ContactsContract.CommonDataKinds.Phone.NUMBER column included in your selection should be causing the exception.
You might want to query a different table from the ContactsContract which is ContactsContract.Data that as stated at the overview from the ContactsContract
A row in the ContactsContract.Data table can store any kind of personal data, such as a phone number or email addresses.
Change Your Query URI.
You are using a URI that is not meant for searching/filtering Contacts and does not have access to those columns:
Uri uri = ContactsContract.Contacts.CONTENT_URI;
You need to use a URI that has access to the columns you're trying to filter on, like this:
Uri uri = ContactsContract.Data.CONTENT_URI;
There's a decent breakdown of what URIs to use and when on the Android SDK Documentation:
If you need to read an individual contact, consider using CONTENT_LOOKUP_URI instead of CONTENT_URI.
If you need to look up a contact by the phone number, use PhoneLookup.CONTENT_FILTER_URI, which is optimized for this purpose.
If you need to look up a contact by partial name, e.g. to produce filter-as-you-type suggestions, use the CONTENT_FILTER_URI URI.
If you need to look up a contact by some data element like email address, nickname, etc, use a query against the ContactsContract.Data table. The result will contain contact ID, name etc.
I want to retrieve all the contacts in an Android phone along with all their phone numbers. Let's say following is the list of contacts on my phone along with their phone numbers:
A - 1111 (Mobile), 2222(Home), 3333(Work)
B - 4444 (Mobile), 5555(Home)
C - 6666 (Mobile), 7777(Home), 8888(Work)
I want to display the contacts in the following fashion but using CursorLoader.
Things I have tried :
Get all the contacts and their phone numbers at a time and save them in an array list of custom contact objects and use them to display the list in a RecyclerView.
Issue with this is that if there are a lot of phone numbers then re-visiting this screen causes a blank screen possibly either due to resource not being free or memory leak issues.
Stack Overflow won't indent the code properly so here it is: https://pastebin.com/y9i5R5iN
final Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactListCursor.getLong(ContactsQuery.ID)));
Uri thisContactUri = ContactsContract.Contacts.lookupContact(context.getContentResolver(), uri);
final UserContact contact = new UserContact();
contact.setName(contactListCursor.getString(contactListCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
final ArrayList<PhoneType> multipleContacts = new ArrayList<>();
final Uri phoneNumUri = Uri.withAppendedPath(thisContactUri, ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
final Cursor contactPhoneNumCursor = contentResolver.query(phoneNumUri, ContactPhoneQuery.PROJECTION, ContactPhoneQuery.SELECTION, null, null);
Get all the contacts using a CursorLoader and a CursorAdapter by querying the ContactsContract.Contacts.CONTENT_URI and getting the ID and DISPLAY_NAME_PRIMARY. In the getView() method I thought I could initialize a second CursorLoader to call into the details of the contact that the first cursor has given me. Something like this :
IF the user has multiple contacts then show a list of radio buttons, else show a textview with the only number they have.
This seems to load the phone numbers in advance and not update the view later on. Either because there's a delay or something I am not sure.
Found a way to do it.
Used the CursorLoader to pass to the CustomAdapter for initial query of contacts and then used the _ID field to lookup the contact and created a URI for the contact and looked up the Phone specific details inside the CustomAdapter's getView method itself.
I was trying to use CursorLoaders in both or Bulk loads in both. The hybrid approach worked out best.
Hope this helps someone. :)
You can use a single query to get all phone numbers in the Database along with their contact-ids and contact-names.
I would run this single query once, store all data in a map (contact-id => name, phone, ...)
And then use a custom adapter to display the map as a list of contacts.
Here's the code for querying all phones along with contact-ids and names (make sure you import everything from ContactsContract):
Map<Long, List<String>> contacts = new HashMap<Long, List<String>>();
String[] projection = { Data.CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3 };
String selection = Data.MIMETYPE + " IN ('" + Phone.CONTENT_ITEM_TYPE + "')";
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1);
String mime = cur.getString(2); // type of data (e.g. "phone")
String data = cur.getString(3); // the actual info, e.g. +1-212-555-1234
int type = cur.getInt(4); // a numeric value representing type: e.g. home / office / personal
String label = cur.getString(5); // a custom label in case type is "TYPE_CUSTOM"
String labelStr = Phone.getTypeLabel(getResources(), type, label);
Log.d(TAG, "got " + id + ", " + name + ", " + kind + " - " + data + " (" + labelStr + ")");
// add info to existing list if this contact-id was already found, or create a new list in case it's new
List<String> infos;
if (contacts.containsKey(id)) {
infos = contacts.get(id);
} else {
infos = new ArrayList<String>();
infos.add("name = " + name);
contacts.put(id, infos);
}
infos.add(kind + " = " + data + " (" + labelStr + ")");
}
Note: The map's value is a list of strings, just for code-clarity. You should change it to be a custom Contact object that holds the name and list of phones in a proper Java Object
I am trying to delete a row from my table if 2 columns equal to what the user entered.
E.g. I have 2 textfields in which the user entered something in both e.g. "chicken" and in the other textfield "car". I want to delete the row in which those 2 values are in a row. I think it will be something like: delete from ~tablename~ where food = chicken AND vehicle = car.
Im not sure how to write that in sqlite in android.
I have my SQLitedatabase object and have called the delete method on it, but not sure what to put in the parameters
EDIT = I've managed to do it. Thanks for the below answers but this is how I've done it:
sqlitedb.delete("Random", "food =? AND vehicle=? ", new String[]{tv.getText.toString(),tv1.getText.toString()});
tv and tv1 are textfields in my case. Random is my table's name.
The sql query will look like -
String sqlQuery = "DELETE FROM <table_name> WHERE food = '"+ <food_name> + "' AND vehicle = '" + <vehicle_name> + "'";
You want something like:
String table_name=~tablename~;
String table_column_one=food;
String table_column_two=vehicle;
database.delete(table_name,
table_column_one + " = ? AND " + table_column_two + " = ?",
new String[] {"chicken", "car"});
Check SQLiteDatabase's documentation on delete function for more info.
SQLite accepts conditionals in the WHERE clause as regular SQL.
I have a simple chat application. I am using content loaders to display messages inside a channel. Since I want 100 recent messages I sort messages based on the time stamp desc and limit it to 100. but I want to display recent messages at the bottom of the screen. Right now the cursor adaptor displays recent message first. How do I reverse the order of the cursor ?
According to me, I will have to write some smart query inside content provider or somehow have to manipulate the cursor inside cursor adaptor's bindView.
Try to sort your messages based on timestamp ASC instead of DESC.
edit: Sorry, didn't grasp the subtility here.
You can try something like this to get data in reverse order:
for (cursor.moveToLast(); !cursor.isBeforeFirst(); cursor.moveToPrevious())
{
// do your magic
}
I would probably use subquery
SELECT * FROM table ORDER BY timestamp WHERE _id
IN (SELECT _id FROM table ORDER BY timestamp DESC LIMIT 100)
To use that with content provider:
String sel = BaseColumns._ID + " IN (SELECT " + BaseColumns._ID +
" FROM " + MyDb.TableName._TABLE_NAME + " ORDER BY " +
MyDb.TableName.TIMESTAMP + " DESC LIMIT 100)";
Cursor q = getContentResolver().query(MyDb.TableName.CONTENT_URI,
null, sel, null, MyDb.TableName.TIMESTAMP);
MyDb is yours class defining tables and its fields, UriS etc.