Sembra che tu abbia trovato una funzione che è stata documentata in molti posti, ma che non era ancora stata implementata. Ho aperto un bug per tenere traccia di questo problema - vediamo cosa hanno da dire i ragazzi AOSP sull'argomento (bug report).
Nel frattempo, è possibile utilizzare la seguente soluzione:
Uri uri = ContactsContract.RawContactsEntity.CONTENT_URI;
String[] projection = {
Phone._ID,
Phone.DELETED,
//Phone.LOOKUP_KEY,
Phone.NUMBER,
Phone.TYPE,
Phone.LABEL,
Data.MIMETYPE,
Data.DISPLAY_NAME_PRIMARY
};
String selection = Data.MIMETYPE + " = ? AND " + Data.DELETED + " = ?";
String[] args = {
Phone.CONTENT_ITEM_TYPE, "0"
};
return new CursorLoader(
this,
uri,
projection,
selection,
args,
null);
Modifiche:
- Usa RawContactsEntity's URI
LOOKUP_KEY
non è accessibile via sopra URI - dovrete eseguire query aggiuntiva se hai assolutamente bisogno di questa colonna
_ID
colonna sarà necessaria se si intende utilizzare th e risultante Cursor
in CursorAdapter
.
Edit: dopo @ richiesta di MichaelAlanHuff sto postando le parti di codice che questa risposta si basa su
Da com.android.providers.contacts.ContactsProvider2#queryLocal()
(codice sorgente di ContactsProvider2):
protected Cursor queryLocal(final Uri uri, final String[] projection, String selection,
String[] selectionArgs, String sortOrder, final long directoryId,
final CancellationSignal cancellationSignal) {
final SQLiteDatabase db = mDbHelper.get().getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String groupBy = null;
String having = null;
String limit = getLimit(uri);
boolean snippetDeferred = false;
// The expression used in bundleLetterCountExtras() to get count.
String addressBookIndexerCountExpression = null;
final int match = sUriMatcher.match(uri);
switch (match) {
...
case DATA:
case PROFILE_DATA:
{
final String usageType = uri.getQueryParameter(DataUsageFeedback.USAGE_TYPE);
final int typeInt = getDataUsageFeedbackType(usageType, USAGE_TYPE_ALL);
setTablesAndProjectionMapForData(qb, uri, projection, false, typeInt);
if (uri.getBooleanQueryParameter(Data.VISIBLE_CONTACTS_ONLY, false)) {
qb.appendWhere(" AND " + Data.CONTACT_ID + " in " + Tables.DEFAULT_DIRECTORY);
}
break;
}
...
}
qb.setStrict(true);
// Auto-rewrite SORT_KEY_{PRIMARY, ALTERNATIVE} sort orders.
String localizedSortOrder = getLocalizedSortOrder(sortOrder);
Cursor cursor = query(db, qb, projection, selection, selectionArgs, localizedSortOrder, groupBy,
having, limit, cancellationSignal);
if (readBooleanQueryParameter(uri, Contacts.EXTRA_ADDRESS_BOOK_INDEX, false)) {
bundleFastScrollingIndexExtras(cursor, uri, db, qb, selection,
selectionArgs, sortOrder, addressBookIndexerCountExpression,
cancellationSignal);
}
if (snippetDeferred) {
cursor = addDeferredSnippetingExtra(cursor);
}
return cursor;
}
Come si può vedere, ci sono due metodi aggiuntivi in cui SQLiteQueryBuilder utilizzato per costruire la query potrebbe essere modificato: setTablesAndProjectionMapForData()
e ulteriore metodo.
Fonte di com.android.providers.contacts.ContactsProvider2#setTablesAndProjectionMapForData()
:
private void setTablesAndProjectionMapForData(SQLiteQueryBuilder qb, Uri uri,
String[] projection, boolean distinct, boolean addSipLookupColumns, Integer usageType) {
StringBuilder sb = new StringBuilder();
sb.append(Views.DATA);
sb.append(" data");
appendContactPresenceJoin(sb, projection, RawContacts.CONTACT_ID);
appendContactStatusUpdateJoin(sb, projection, ContactsColumns.LAST_STATUS_UPDATE_ID);
appendDataPresenceJoin(sb, projection, DataColumns.CONCRETE_ID);
appendDataStatusUpdateJoin(sb, projection, DataColumns.CONCRETE_ID);
appendDataUsageStatJoin(
sb, usageType == null ? USAGE_TYPE_ALL : usageType, DataColumns.CONCRETE_ID);
qb.setTables(sb.toString());
boolean useDistinct = distinct || !ContactsDatabaseHelper.isInProjection(
projection, DISTINCT_DATA_PROHIBITING_COLUMNS);
qb.setDistinct(useDistinct);
final ProjectionMap projectionMap;
if (addSipLookupColumns) {
projectionMap =
useDistinct ? sDistinctDataSipLookupProjectionMap : sDataSipLookupProjectionMap;
} else {
projectionMap = useDistinct ? sDistinctDataProjectionMap : sDataProjectionMap;
}
qb.setProjectionMap(projectionMap);
appendAccountIdFromParameter(qb, uri);
}
Qui si vede la costruzione di table
argomento della query finale utilizzando StringBuilder
che viene passato a diversi append*()
metodi. Non pubblicherò il loro codice sorgente, ma sono davvero le join
le tabelle che compaiono nei nomi dei metodi. Se la tabella rawContacts
si unisse, mi aspetterei di vedere una chiamata a qualcosa come appendRawContactJoin()
qui ...
Per completezza: l'altra query()
metodo che ho citato non modifica table
argomento:
private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection,
String selection, String[] selectionArgs, String sortOrder, String groupBy,
String having, String limit, CancellationSignal cancellationSignal) {
if (projection != null && projection.length == 1
&& BaseColumns._COUNT.equals(projection[0])) {
qb.setProjectionMap(sCountProjectionMap);
}
final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, having,
sortOrder, limit, cancellationSignal);
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI);
}
return c;
}
L'ispezione della catena sopra dei metodi mi ha portato alla conclusione che v'è una caratteristica ufficialmente documentato che non è implementato.
Si tratta di più dispositivi? –
@MichaelAlanHuff - sì, ho provato su due dispositivi. Android 5.0 e 5.1. – Gautam