I have the ID of a contact group, and I'd like to list its members. Here's the code I'm trying:
String[] projection = new String[]{
ContactsContract.CommonDataKinds.GroupMembership.CONTACT_ID
};
Cursor contacts = getContentResolver().query(
Data.CONTENT_URI,
projection,
ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID + "=" + gid,
null,
null
);
String result = "";
do {
result += contacts.getString(contacts.getColumnIndex(ContactsContract.CommonDataKinds.GroupMembership.CONTACT_ID)) + " ";
} while (contacts.moveToNext());
But this throws an Exception:
03-24 17:11:33.097: ERROR/AndroidRuntime(10730): android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 2
...
03-24 17:11:33.097: ERROR/AndroidRuntime(10730): at myapp.MultiSend$1.onItemClick(MultiSend.java:83)
which is the line starting result +=. Can anyone tell me what I'm doing wrong, or suggest a better way to get the same information?
Try this code snippet
String[] projection = new String[]{
ContactsContract.CommonDataKinds.GroupMembership.CONTACT_ID
};
Cursor contacts = getContentResolver().query(
Data.CONTENT_URI,
projection,
ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID + "=" + gid,
null,
null
);
startManagingCursor(contacts);
String result = "";
if (contacts.moveToFirst()) {
do {
try {
result += contacts.getString(contacts.getColumnIndex(ContactsContract.CommonDataKinds.GroupMembership.CONTACT_ID)) + " ";
} catch (Exception ex) {
ex.printStackTrace();
}
} while (contacts.moveToNext());
}
Cursor.getColumnIndex(String column) returns -1 when the column does not exist, and that is causing Cursor.getString(int colidx) to throw the exception.
I'd start testing by passing null for the third argument of the query call to see if you get a valid Cursor from the call.
If you don't get a valid Cursor, then I'd check to make sure that Data.CONTENT_URI is the right CONTENT_URI to call. It's hard to tell what the fully qualified path is without seeing your imports. (Edit: It looks like ContactsContract.Data.CONTENT_URI must be the constant there.)
If you do get a valid Cursor, then there might be an issue with that third argument.
Related
** Edit**
This is the URI in question: ContactsContract.Data.CONTENT_URI
Is there any way of knowing if a contact is marked for deletion from this URI?
I already tried querying for the DELETED column, but it crashes with an SQL exception
Thanks for your help
** Attached code **
ContentQuery contentQuery = new ContentQuery(ContactsContract.Data.CONTENT_URI)
.column(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)
.column(ContactsContract.CommonDataKinds.Phone.NUMBER)
.column(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
.column(ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY)
.column(CommonDataKinds.Note.NOTE)
.column(Data.MIMETYPE)
.column(ContactsContract.CommonDataKinds.Phone.STARRED)
.where(ContactsContract.CommonDataKinds.Phone.DELETED, "=", "1");
Where ContentQuery is a query builder interface
I haven't tried it, but to get the implicit join of the DELETED field from RawContacts as mentioned in the docs, you need to add RawContacts.DELETED to your projection.
Check the following code, it should print data belonging to deleted contacts:
String[] projection = new String[] { Phone.CONTACT_ID, Phone.DISPLAY_NAME, Phone.NUMBER, RawContact.DELETED };
Cursor cur = contentResolver.query(ContactsContract.Data.CONTENT_URI, projection, null ,null, null);
while (cur.moveToNext()) {
if (cur.getInt(3) == 1) {
Log.i("TAG", "found a deleted data row: " + cur.getLong(0) + ", " + cur.getString(1) + ", " + cur.getString(2));
}
}
cur.close();
I am using the following to fetch a string from my table. The cursor is always returning empty even when I have data in database. Is the query wrong?
public void find(String myNumber){
String[] thecolumns = new String[]{
ID,
FLAG};
cursor = sqlDb.query(MY_TABLE,
thecolumns, NUMBER + "='"
+ myNumber+ "'", null, null, null, null);
if (cursorToFetchAssets != null ) {
cursorToFetchAssets.moveToFirst();{
try{
//code to fetch
}catch{
//return when there are no rows found.
}
}
EDIT: NUMBER is of type string "...+ NUMBER + " TEXT,.. " and myNumber is also a string
FIXED: Issue was on the server side of my code. Not over here..
try this:
cursor = sqlDb.query(
MY_TABLE,
thecolumns,
NUMBER + "=?",
new String[]{String.valueOf(number)},
null, null, null);
I use one in my sqlite database a config table. This has the following composition:
private static final String DATABASE_CONFIG_CREATE =
"CREATE TABLE " + TABLE_CONFIGS
+ "("
+ CONFIG_HIDDEN_CATEGORIES + " TEXT DEFAULT '1,2' NULL"
+ ");";
Later I try to access with the following code:
Cursor cursor = database.query(DatabaseHelper.TABLE_CONFIGS, new String[] {DatabaseHelper.CONFIG_HIDDEN_CATEGORIES}, null, null, null, null, null);
try {
cursor.moveToFirst();
int test = cursor.getCount();
String data = cursor.getString(0);
}
catch (Exception exception) {
But the line cursor.getString(0) throws the following exeption (variable test is 0):
android.database.CursorIndexOutOfBoundsException: Index 0 requested,
with a size of 0
when I run the following code, the column CONFIG_HIDDEN_CATEGORIES is displayed to me... what is wrong?
Cursor dbCursor = database.query(DatabaseHelper.TABLE_CONFIGS, null, null, null, null, null, null);
String[] columnNames = dbCursor.getColumnNames(); // index 0 is the value of CONFIG_HIDDEN_CATEGORIES
It means that your Cursor is empty. You should wrap your actions to correct condition:
try {
if (cursor.moveToFirst()) {
String data = cursor.getString(cursor.getColumnIndex("columnName"));
// do your stuff
}
else {
// cursor is empty
}
}
...
Your actual code won't work correct because you just calling moveToFirst() method but you don't know (are not testing) if it'll return true or false.
Your code works correct only if Cursor is not empty. In second case it won't work.
Note: I recommend you to use getColumnIndex(<columnName>) method for getting column index due to its name. This method is safer and more human-readable.
I have an issue where when I execute my query with a WHERE clause it returns no results but if I leave the WHERE as null it will execute through all of my records and find the match. Can anyone tell me what is wrong with my query?
in my code lets say that contactURI is equal to "content://com.android.contacts/contacts/lookup/953i7d73a639091bc5b6/164" and contactUriId is equal to "164"
// Put data in the contactURI
contactURI = data.getData();
// get the contact id from the URI
contactUriId = contactURI.getLastPathSegment();
//TEST TODO Fix URI Issue
String [] PROJECTION = new String [] { Data.CONTACT_ID, Data.LOOKUP_KEY };
Cursor cursor = this.managedQuery(Data.CONTENT_URI, PROJECTION, Data.CONTACT_ID + "=?" + " AND "
+ Data.MIMETYPE + "='*'",
new String[] { String.valueOf(contactUriId) }, null);
Log.e(DEBUG_TAG, contactUriId+"-164-");
for(cursor.moveToFirst(); cursor.moveToNext(); cursor.isAfterLast()) {
Log.v(DEBUG_TAG, "lookupKey for contact: " + cursor.getString(1) + " is: -" + cursor.getString(0) + "-");
if(cursor.getString(0).equals("164")){
Log.e(DEBUG_TAG, "WE HAVE A MATCH");
}
}
This is my log...
05-14 19:08:40.764: D/OpenGLRenderer(21559): Flushing caches (mode 0)
05-14 19:08:46.944: E/MyDebug(22269): 164-164-
The problem is with this:
Data.MIMETYPE + "='*'"
That is searching for MIMETYPEs literally named *. If you want to select all MIMETYPEs, don't do anything. A query returns all of these rows by default.
Also, this loop seems to execute, but it is not quite right:
for(cursor.moveToFirst(); cursor.moveToNext(); cursor.isAfterLast()) {
Since cursor has not been move from index -1. This will safely start at the beginning and iterate until the last row:
while(cursor.moveToNext()) {
If you have moved cursor and want to start from the beginning again you can use:
for(cursor.moveToFirst(); cursor.moveToNext(); ) {
Detailed Explanation Why: cursor.isAfterLast() does not move the cursor, it simply checks if the cursor is still referring to valid data. cursor.moveToNext() moves the cursor to the next row and returns true if the cursor is still in bounds. (In other words if cursor.isAfterLast() is true then cursor.moveToNext() returns false.)
Is possible to use an IN clause for a content provider?
I am currently using
cursor = contentResolver.query(CONTENT_URI, PROJECTION, "field IN (?)", new String[] { argsBuilder.toString() }, null);
If i remove the (?) and just use ? I get an error.
I get 0 count in my cursor.
If I type manually and execute the query in sqlite3 it works.
Help?
When using the IN operator, you need to have one ? separated by a comma per argument you provide in your selectionArgs array. E.g.:
String[] selectionArgs = {"red", "black"};
String selection = "color IN (?, ?)";
The following picks the right count and the proper args:
int argcount = 2; // number of IN arguments
String[] args = new String[]{ 1, 2 };
StringBuilder inList = new StringBuilder(argcount * 2);
for (int i = 0; i < argcount; i++) {
if(i > 0) {
inList.append(",");
}
inList.append("?");
}
cursor = contentResolver.query(
CONTENT_URI,
PROJECTION,
"field IN (" + inList.toString() + ")",
args,
null);
If your arguments are numbers only, this works as well:
Iterable args = ...; // any array, list, set, ...
cursor = contentResolver.query(CONTENT_URI, PROJECTION, "field IN (" + TextUtils.join(",", args) + ")", null, null);
This is a code snippet from my application built in Kotlin, the params array is for illustration purposes only as the parameters come from elsewhere in the code.
The problem with most of the proposed solutions is that they result in the loss of the SQL injection prevention that the use of placeholders provides, so I only use an expression that returns an array of "?" and whose quantity matches the array of provided parameters and then becomes a comma separated String.
That way, the delivered string is a string of placeholders and not the parameters directly.
Sorry for my first answer write in spanish.
var params = arrayOf("1789","1787","1694","1784")
applicationContext.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null,
"_ID IN (" + Array(params.size) { "?" }.joinToString() + ")",
params,
null
)