Alright, I'm a little new to the Android SDK, so forgive me if my question doesn't make sense or is very trivial. I'd like to add a custom field for contacts, that contains the contacts username on a website I'm doing this app for. And, with this custom field, I'd like to have the ability to click it (like "Send message" or "Call mobile") so that I can go to a specif Activity in my application, with a TextView set with the username that I just clicked on.
Sorry if that is a bit confusing, if you need anything else let me know!
It's working! But I changed Data.CONTACT_ID to Data.RAW_CONTACT_ID here:
if (mod == 0) {
values.put(Data.CONTACT_ID, this.getId());
values.put(Data.MIMETYPE, clsContacts.FORMALITY_MIMETYPE);
ctx.getContentResolver().insert(Data.CONTENT_URI, values);
}
You have to creat your own mime type for those.
Here is an example that saves a boolean as my custom mime type to the contacts. It uses the latest SDK 2.1
public static final String MIMETYPE_FORMALITY = "vnd.android.cursor.item/useformality";
public clsMyClass saveFormality() {
try {
ContentValues values = new ContentValues();
values.put(Data.DATA1, this.getFormality() ? "1" : "0");
int mod = ctx.getContentResolver().update(
Data.CONTENT_URI,
values,
Data.CONTACT_ID + "=" + this.getId() + " AND "
+ Data.MIMETYPE + "= '"
+ clsContacts.FORMALITY_MIMETYPE + "'", null);
if (mod == 0) {
values.put(Data.CONTACT_ID, this.getId());
values.put(Data.MIMETYPE, clsContacts.FORMALITY_MIMETYPE);
ctx.getContentResolver().insert(Data.CONTENT_URI, values);
}
} catch (Exception e) {
Log.v(TAG(), "saveFormality failed");
}
return this;
}
public boolean getFormality() {
if (data.containsKey(FORMALITY)) {
return data.getAsBoolean(FORMALITY);
} else {
// read formality
Cursor c = readDataWithMimeType(clsContacts.MIMETYPE_FORMALITY, this.getId());
if (c != null) {
try {
if (c.moveToFirst()) {
this.setFormality(c.getInt(0) == 1);
return (c.getInt(0) == 1);
}
} finally {
c.close();
}
}
return false;
}
}
public clsMyClass setFormality(Boolean value) {
data.remove(FORMALITY);
data.put(FORMALITY, value);
return this;
}
/**
* Utility method to read data with mime type
*
* #param mimetype String representation of the mimetype used for this type
* of data
* #param contactid String representation of the contact id
* #return
*/
private Cursor readDataWithMimeType(String mimetype, String contactid) {
return ctx.getContentResolver().query(
Data.CONTENT_URI,
new String[] {
Data.DATA1
},
Data.RAW_CONTACT_ID + "=" + contactid + " AND " + Data.MIMETYPE + "= '" + mimetype
+ "'", null, null);
}
Usage is
objContact.setFormality(true).saveFormality();
To add custom field you need to add custom mimetype in MIMETYPE table. But we dont have direct access to MIMETYPE table. so following can be done:
public static final String MIMETYPE="vnd.android.cursor.item/favsong";
ContentValues values = new ContentValues();
values.put(Data.RAW_CONTACT_ID, id);
values.put(Data.MIMETYPE, MIMETYPE);
values.put(Data.DATA1, "MyFavSong");
Uri dataUri = getContentResolver().insert(Data.CONTENT_URI, values);
what we have done is , we have created a custom MIMETYPE as string constant.
Then using insert query we are inserting a new row in Data table having RAW_CONTACT_ID of a person we want to associate our custom field , in MIMETYPE column we put our own mimetype and in DATA1 column we put favourite song . here system internally add the new mimetype in MIMETYPE table and give it an ID and that ID is used in mimetype_id column of Data table.
Related
public boolean findContact(String phoneNumber) {
boolean exists = false;
Cursor mCursor = mDb.rawQuery("SELECT * FROM " + SQLITE_TABLE + " WHERE " + KEY_PHONENUMBER + " = " + phoneNumber, null);
if (mCursor.moveToFirst()) {
exists = true;
} else exists = false;
return exists;
}
It is supose to return true when a row with telephone number exists (format is +441212312312 - String ). The problem is that it always return false, even if such a row exists. I think that a problem is with WHERE clause, but LIKE don't work either. How can I do this ?
thanks for your response
i suggest you that use query, insert, update or delete clauses directly from SQLiteDatabase object instance ;)
And see link below to know which values you will have returned
SQLiteDatabase Object
And i suggest too that if you just want if it exists don't ask about * ... ask about _id because it's primary key it has a index ;)) <-- it means faster
Here i seek a specific row:
public Cursor getEnvio(final String empresa_p, final String albaran_p) {
return db.query(Envio.KEY_ENVIO, new String[] { Envio.KEY_ID,
Envio.KEY_ALBARAN, Envio.KEY_LINEA, Envio.KEY_TIPO,
Envio.KEY_DESTINATARIO, Envio.KEY_DIR, Envio.KEY_POBLACION,
Envio.KEY_POBLACION, Envio.KEY_PRIORIDAD, Envio.KEY_INCIDENCIA,
Envio.KEY_EMP, Envio.KEY_CPOSTAL }, Envio.KEY_EMP + " = ? AND "
+ Envio.KEY_ALBARAN + " = ? ", new String[] { empresa_p,
albaran_p }, null, null, Envio.KEY_LINEA);
}
In my code I update contact information including name, address, email, and photo. When contact have no photo all OK. But after assigning a photo for the contact I get android.database.sqlite.SQLiteException: unknown error: Unable to convert BLOB to string on each update operation.
My code for adding photo to contact
Bitmap bit =getBitmap();
ByteArrayOutputStream streamy = new ByteArrayOutputStream();
bit.compress(CompressFormat.PNG, 0, streamy);
byte[] photo = streamy.toByteArray();
ContentValues values = new ContentValues();
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
values.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, photo);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
try {
if (getPhotoUri(rawContactId) != null) {
ContactHelper.context.getContentResolver().update(ContactsContract.Data.CONTENT_URI, values,
String.format("%s = ?", ContactsContract.Data.RAW_CONTACT_ID), new String[] {String.format("%d", rawContactId)});
} else {
ContactHelper.context.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
}
} catch (Exception ex) {
ex.printStackTrace();
}
My code to change contact name
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add( ContentProviderOperation.newUpdate( Data.CONTENT_URI )
.withSelection( Data.RAW_CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'",
new String[] { String.valueOf( rawContactId ) } )
.withValue( ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.getName() )
.build() );
try {
ContentResolver cr = context.getContentResolver();
cr.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
e.printStackTrace();
}
There is a nice little blog entry on ThinkAndroid that will show you how to do this:
http://thinkandroid.wordpress.com/2009/12/30/handling-contact-photos-all-api-levels/
The core part is this:
public static void setContactPhoto(ContentResolver c, byte[] bytes, long personId) {
ContentValues values = new ContentValues();
int photoRow = -1;
String where = ContactsContract.Data.RAW_CONTACT_ID + " = " + personId + " AND " + ContactsContract.Data.MIMETYPE + "=='" + ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'";
Cursor cursor = c.query(ContactsContract.Data.CONTENT_URI, null, where, null, null);
int idIdx = cursor.getColumnIndexOrThrow(ContactsContract.Data._ID);
if (cursor.moveToFirst()) {
photoRow = cursor.getInt(idIdx);
}
cursor.close();
values.put(ContactsContract.Data.RAW_CONTACT_ID, personId);
values.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
if (photoRow >= 0) {
c.update(ContactsContract.Data.CONTENT_URI, values, ContactsContract.Data._ID + " = " + photoRow, null);
} else {
c.insert(ContactsContract.Data.CONTENT_URI, values);
}
}
Basically, what you can’t just do is:
ContentValues values = new ContentValues();
values.put(ContactsContract.Data.RAW_CONTACT_ID, personId);
values.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes.toByteArray());
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE );
context.getContentResolver().update(ContactsContract.Data.CONTENT_URI, values, ContactsContract.Data.RAW_CONTACT_ID + " = " + personId, null);
And that’s because there are many rows where the RAW_CONTACT_ID = personId (there are data rows for the photo, phone numbers, emails, etc) and so trying this should give you some kind of SQLite exception along the lines of “CANNOT CONVERT BLOB TO STRING” and this makes sense as in this case you’re probably trying to update the phone number row with these bytes and so it’s throwing the appropriate error. Thus, in the first example, you need to begin by identifying which of these rows where RAW_CONTACT_ID = personId contains the BLOB value of the photo, and in the second query you want to set it in that row specifically. Now notice that sometimes photoRow may come back as -1. This basically tells us that no one has tried to set the photo or any other information before, and so we simply need to do a getContentResolver.insert(). Now, exactly why the behavior is different in these two cases, I don’t know. But the code above works, so once Google releases some better documentation maybe we’ll find out!
I want to fetch All Contacts atleast with one phone Number, also I want all Phone Numbers and All emails for every Contact.
Current code :
// To get All Contacts having atleast one phone number.
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " > ?";
String[] selectionArgs = new String[] {"0"};
Cursor cu = applicationContext.getContentResolver().query(uri,
null, selection, selectionArgs, null);
// For getting All Phone Numbers and Emails further queries :
while(cu.moveToNext()){
String id = cu.getString(cu.getColumnIndex(ContactsContract.Contacts._ID));
// To get Phone Numbers of Contact
Cursor pCur = context.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?",
new String[]{id}, null);
// To get Email ids of Contact
Cursor emailCur = context.getContentResolver().query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?",
new String[]{id}, null);
// Iterate through these cursors to get Phone numbers and Emails
}
If there are more than 1000 contacts in my Device, it is taking too much time. How can I get All Data in single query, rather than doing two additional queries for each contact?
Or is there any other way to optimize?
Thank you in Advance.
ICS: When you query from Data.CONTENT_URI you have all the rows from the associated Contact already joined - i.e. this would work:
ContentResolver resolver = getContentResolver();
Cursor c = resolver.query(
Data.CONTENT_URI,
null,
Data.HAS_PHONE_NUMBER + "!=0 AND (" + Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=?)",
new String[]{Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE},
Data.CONTACT_ID);
while (c.moveToNext()) {
long id = c.getLong(c.getColumnIndex(Data.CONTACT_ID));
String name = c.getString(c.getColumnIndex(Data.DISPLAY_NAME));
String data1 = c.getString(c.getColumnIndex(Data.DATA1));
System.out.println(id + ", name=" + name + ", data1=" + data1);
}
If you are targeting 2.3 you need to account for the fact that HAS_PHONE_NUMBER is not available through the joins used when querying Data.
Fun.
This could, for instance, be solved either by skipping your requirement that the contact must have a phone number and instead settle for "any contact with at least a phone number or an e-mail address":
Cursor c = resolver.query(
Data.CONTENT_URI,
null,
Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=?",
new String[]{Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE},
Data.CONTACT_ID);
If that is not an option you can always go for a horribly hacky sub-select:
Cursor c = resolver.query(
Data.CONTENT_URI,
null,
"(" + Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=?) AND " +
Data.CONTACT_ID + " IN (SELECT " + Contacts._ID + " FROM contacts WHERE " + Contacts.HAS_PHONE_NUMBER + "!=0)",
new String[]{Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE}, Data.CONTACT_ID);
or solve it by using two Cursors:
Cursor contacts = resolver.query(Contacts.CONTENT_URI,
null, Contacts.HAS_PHONE_NUMBER + " != 0", null, Contacts._ID + " ASC");
Cursor data = resolver.query(Data.CONTENT_URI, null,
Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=?",
new String[]{Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE},
Data.CONTACT_ID + " ASC");
int idIndex = contacts.getColumnIndexOrThrow(Contacts._ID);
int nameIndex = contacts.getColumnIndexOrThrow(Contacts.DISPLAY_NAME);
int cidIndex = data.getColumnIndexOrThrow(Data.CONTACT_ID);
int data1Index = data.getColumnIndexOrThrow(Data.DATA1);
boolean hasData = data.moveToNext();
while (contacts.moveToNext()) {
long id = contacts.getLong(idIndex);
System.out.println("Contact(" + id + "): " + contacts.getString(nameIndex));
if (hasData) {
long cid = data.getLong(cidIndex);
while (cid <= id && hasData) {
if (cid == id) {
System.out.println("\t(" + cid + "/" + id + ").data1:" +
data.getString(data1Index));
}
hasData = data.moveToNext();
if (hasData) {
cid = data.getLong(cidIndex);
}
}
}
}
I went through the exact same problem. Since then I build my own solution which is inspired from this post yet a bit different. Now I'd like to share it as my first StackOverFlow answer :-)
Its quite similar to the double cursor approach suggested by Jens. The idea is to
1- fetch relevant contact from the Contacts table
2- fetch relevant Contacts information (mail, phone, ...)
3- combine these results
The "relevant" is up to you of course but the important point is the performance !
Besides, I'm sure other solutions using well suited SQL query might as well do the job but here I only want to use the Android ContentProvider
Here is the code :
Some constants
public static String CONTACT_ID_URI = ContactsContract.Contacts._ID;
public static String DATA_CONTACT_ID_URI = ContactsContract.Data.CONTACT_ID;
public static String MIMETYPE_URI = ContactsContract.Data.MIMETYPE;
public static String EMAIL_URI = ContactsContract.CommonDataKinds.Email.DATA;
public static String PHONE_URI = ContactsContract.CommonDataKinds.Phone.DATA;
public static String NAME_URI = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ? ContactsContract.Data.DISPLAY_NAME_PRIMARY : ContactsContract.Data.DISPLAY_NAME;
public static String PICTURE_URI = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) ? ContactsContract.Contacts.PHOTO_THUMBNAIL_URI : ContactsContract.Contacts.PHOTO_ID;
public static String MAIL_TYPE = ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE;
public static String PHONE_TYPE = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;
1 Contact
Here I require that the Contacts must have DISPLAY_NAME free of "#" and that their informations match a given string (these requirement can of course be modified). The result of the following method is the first cursor :
public Cursor getContactCursor(String stringQuery, String sortOrder) {
Logger.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
Logger.e(TAG, "ContactCursor search has started...");
Long t0 = System.currentTimeMillis();
Uri CONTENT_URI;
if (stringQuery == null)
CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
else
CONTENT_URI = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI, Uri.encode(stringQuery));
String[] PROJECTION = new String[]{
CONTACT_ID_URI,
NAME_URI,
PICTURE_URI
};
String SELECTION = NAME_URI + " NOT LIKE ?";
String[] SELECTION_ARGS = new String[]{"%" + "#" + "%"};
Cursor cursor = sContext.getContentResolver().query(CONTENT_URI, PROJECTION, SELECTION, SELECTION_ARGS, sortOrder);
Long t1 = System.currentTimeMillis();
Logger.e(TAG, "ContactCursor finished in " + (t1 - t0) / 1000 + " secs");
Logger.e(TAG, "ContactCursor found " + cursor.getCount() + " contacts");
Logger.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
return cursor;
}
This query is quite performant as you'll see !
2 Contact Details
Now let's fetch Contact informations. At this point, I dont make any link between the already fetched Contact and the retrieved information : I just fetch all informations form the Data table... Yet, to avoid useless info I still require DISPLAY_NAMES free of "#" and since I'm interested in email and phone I require that the data MIMETYPE to be either MAIL_TYPE or PHONE_TYPE (see Constants). Here is the code :
public Cursor getContactDetailsCursor() {
Logger.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
Logger.e(TAG, "ContactDetailsCursor search has started...");
Long t0 = System.currentTimeMillis();
String[] PROJECTION = new String[]{
DATA_CONTACT_ID_URI,
MIMETYPE_URI,
EMAIL_URI,
PHONE_URI
};
String SELECTION = ContactManager.NAME_URI + " NOT LIKE ?" + " AND " + "(" + MIMETYPE_URI + "=? " + " OR " + MIMETYPE_URI + "=? " + ")";
String[] SELECTION_ARGS = new String[]{"%" + "#" + "%", ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE};
Cursor cursor = sContext.getContentResolver().query(
ContactsContract.Data.CONTENT_URI,
PROJECTION,
SELECTION,
SELECTION_ARGS,
null);
Long t1 = System.currentTimeMillis();
Logger.e(TAG, "ContactDetailsCursor finished in " + (t1 - t0) / 1000 + " secs");
Logger.e(TAG, "ContactDetailsCursor found " + cursor.getCount() + " contacts");
Logger.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
return cursor;
}
Once again you will see that this query is quite fast...
3 Combining
Now let's combine both Contact and their respective informations. The idea is to use HashMap(Key, String) where Key is the Contact id and String is whatever you like (name, email, ...).
First, I run through the Contact cursor (which is alphabetically ordered) and store names and picture uri in two different HashMap. Note also that I store all Contact id's in a List in the very same order that Contacts appear in the cursor. Lets call this list contactListId
I do the same for the Contact informations (mail and email). But now I take care of the correlation between the two cursor : if the CONTACT_ID of an email or phone does not appear in contactListId it is put aside. I check also if the email has already been encountered. Notice that this further selection can introduce asymmetries between the Name/Picture content and the Email/Phone HashMap content but don't worry.
Eventually, I run over the contactListId list and build a list of Contact object taking care of the fact that : a contact must have information (keySet condition) and that the contact must have at least a mail or an email (the case where mail == null && phone == null may appear if the contact is a Skype contact for instance).
And here is the code :
public List<Contact> getDetailedContactList(String queryString) {
/**
* First we fetch the contacts name and picture uri in alphabetical order for
* display purpose and store these data in HashMap.
*/
Cursor contactCursor = getContactCursor(queryString, NAME_URI);
List<Integer> contactIds = new ArrayList<>();
if (contactCursor.moveToFirst()) {
do {
contactIds.add(contactCursor.getInt(contactCursor.getColumnIndex(CONTACT_ID_URI)));
} while (contactCursor.moveToNext());
}
HashMap<Integer, String> nameMap = new HashMap<>();
HashMap<Integer, String> pictureMap = new HashMap<>();
int idIdx = contactCursor.getColumnIndex(CONTACT_ID_URI);
int nameIdx = contactCursor.getColumnIndex(NAME_URI);
int pictureIdx = contactCursor.getColumnIndex(PICTURE_URI);
if (contactCursor.moveToFirst()) {
do {
nameMap.put(contactCursor.getInt(idIdx), contactCursor.getString(nameIdx));
pictureMap.put(contactCursor.getInt(idIdx), contactCursor.getString(pictureIdx));
} while (contactCursor.moveToNext());
}
/**
* Then we get the remaining contact information. Here email and phone
*/
Cursor detailsCursor = getContactDetailsCursor();
HashMap<Integer, String> emailMap = new HashMap<>();
HashMap<Integer, String> phoneMap = new HashMap<>();
idIdx = detailsCursor.getColumnIndex(DATA_CONTACT_ID_URI);
int mimeIdx = detailsCursor.getColumnIndex(MIMETYPE_URI);
int mailIdx = detailsCursor.getColumnIndex(EMAIL_URI);
int phoneIdx = detailsCursor.getColumnIndex(PHONE_URI);
String mailString;
String phoneString;
if (detailsCursor.moveToFirst()) {
do {
/**
* We forget all details which are not correlated with the contact list
*/
if (!contactIds.contains(detailsCursor.getInt(idIdx))) {
continue;
}
if(detailsCursor.getString(mimeIdx).equals(MAIL_TYPE)){
mailString = detailsCursor.getString(mailIdx);
/**
* We remove all double contact having the same email address
*/
if(!emailMap.containsValue(mailString.toLowerCase()))
emailMap.put(detailsCursor.getInt(idIdx), mailString.toLowerCase());
} else {
phoneString = detailsCursor.getString(phoneIdx);
phoneMap.put(detailsCursor.getInt(idIdx), phoneString);
}
} while (detailsCursor.moveToNext());
}
contactCursor.close();
detailsCursor.close();
/**
* Finally the contact list is build up
*/
List<Contact> contacts = new ArrayList<>();
Set<Integer> detailsKeySet = emailMap.keySet();
for (Integer key : contactIds) {
if(!detailsKeySet.contains(key) || (emailMap.get(key) == null && phoneMap.get(key) == null))
continue;
contacts.add(new Contact(String.valueOf(key), pictureMap.get(key), nameMap.get(key), emailMap.get(key), phoneMap.get(key)));
}
return contacts;
}
The Contact object definition is up to you.
Hope this will help and thanks for the previous post.
Correction/Improvement
I forgot to check the phone key set : it should rather looks like
!mailKeySet.contains(key)
replaced by
(!mailKeySet.contains(key) && !phoneKeySet.contains(key))
with the phone keySet
Set<Integer> phoneKeySet = phoneMap.keySet();
I why not add an empty contact cursor check like :
if(contactCursor.getCount() == 0){
contactCursor.close();
return new ArrayList<>();
}
right after the getContactCursor call
I have the following function for SQLite select statement
public Boolean itemFound(String cartId,Long ItemId){
SQLiteDatabase db = this.getReadableDatabase();
Log.d("search",cartId+"--"+ItemId);
try {
String where = COL_ITEM_CART_ID+"='"+cartId+"' and "+COL_ITEM_ID+" ="+ ItemId+"";
Log.d("where===============", where);
String columns[] = new String[] { COL_ITEM_ID,COL_ITEM_NAME, COL_ITEM_PRICE, COL_ITEM_ADDDATE,COL_ITEM_QUANTITY,COL_ITEM_CART_ID }; // > null means * (all)
Cursor c = db.query(TABLE_NAME,
columns ,
COL_ITEM_CART_ID+"='?' and "+ COL_ITEM_ID + "=?" ,
new String[]{cartId,String.valueOf(ItemId)},
null,
null,
COL_ITEM_ADDDATE+" desc");
int numRows = c.getCount();
c.close();
db.close();
if(numRows>0)
return true;
else
return false;
} catch (SQLException e) {
db.close();
return false;
}
}
where the parameters are :
Long type itemId= 9882889921
String type cartId = ca1745ef-24eb-4da8-a1ea-9650d78ba5c0
Despite there is recode with these data. the returned rows is 0 , why ?
You have wrapped a ? in single quotes, change this:
COL_ITEM_CART_ID+"='?' and "+ COL_ITEM_ID + "=?"
The line above is trying to literally match COL_ITEM_CART_ID to a question mark, change it like this:
COL_ITEM_CART_ID + "=? and "+ COL_ITEM_ID + "=?"
The query method will sanitize your data input for you, so when you wrap the ?s with apostrophes, the apostrophes become part of the input string itself. This is causing your query to return 0 rows.
To fix the problem, remove change all instances of '?' to ?.
I'm still very new to android app development, and I have hit a problem I hope u can help me with...
I am trying to retrieve any "Notes" stored against a contact within my phone. I want to check if a contact (current caller) has any notes associated to them, and then either display the contents or do some action depending on the content of them etc...
I have tried the code below as a test to see if the data is retrieved anywhere within my cursor, but although it retrieves some data, I can't see the content of a note - so I guess I'm in the wrong place!
Where I have declared contentID, this is a result of doing a lookup with the code below, and using the id that is recieved.
Uri lookupUri = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, Uri.encode(inCommingNumber));
String[] mPhoneNumberProjection = { Phone._ID, Phone.NUMBER, Phone.DISPLAY_NAME};
Cursor cur = getContentResolver().query(lookupUri , mPhoneNumberProjection, null, null, null);
private boolean hasNote(String contactID){
Boolean noteFound = false;
Cursor noteCur = getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, null, null, null);
if(noteCur.moveToFirst()) {
int numCols = noteCur.getColumnCount();
if(numCols > 0){
for(int x = 0; x < numCols; x++){
Log.d(APP_TAG, " column " + x + " contains: " + noteCur.getString(x));
}
}
noteFound = true;
} else{
Log.d(APP_TAG, "No Note retrieved");
}
noteCur.close();
return noteFound;
}
Apologies, I cant seem to get the code to display properly in this post!!
Any help would be great
I have tried various things, but can't seem to be able to get this data. I have created the note by simply adding it through the normal contact manager. I'm using Android 2.2.
The following code would display the first note for all contacts on your phone:
Cursor contactsCursor = null;
try {
contactsCursor = getContentResolver().query(RawContacts.CONTENT_URI,
new String [] { RawContacts._ID },
null, null, null);
if (contactsCursor != null && contactsCursor.moveToFirst()) {
do {
String rawContactId = contactsCursor.getString(0);
Cursor noteCursor = null;
try {
noteCursor = getContentResolver().query(Data.CONTENT_URI,
new String[] {Data._ID, Note.NOTE},
Data.RAW_CONTACT_ID + "=?" + " AND "
+ Data.MIMETYPE + "='" + Note.CONTENT_ITEM_TYPE + "'",
new String[] {rawContactId}, null);
if (noteCursor != null && noteCursor.moveToFirst()) {
String note = noteCursor.getString(noteCursor.getColumnIndex(Note.NOTE));
Log.d(APP_TAG, "Note: " + note);
}
} finally {
if (noteCursor != null) {
noteCursor.close();
}
}
} while (contactsCursor.moveToNext());
}
} finally {
if (contactsCursor != null) {
contactsCursor.close();
}
}
If you are storing some sort of structured data on the note to take actions on using the free form note field may not be the best approach. With the new contacts contract model you are able to attach your own data fields (in ContactsContract.Data) to a contact just give them your own unique mimetype.