隐式连接列如何与Android联系人数据配合使用?

我正在查询ContactsContract.Data表以查找电话logging。

创build新的CursorLoader时出现错误:

 java.lang.IllegalArgumentException: Invalid column deleted 

我的代码:

 import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Data; ... String[] projection = { Phone.DELETED, Phone.LOOKUP_KEY, Phone.NUMBER, Phone.TYPE, Phone.LABEL, Data.MIMETYPE, Data.DISPLAY_NAME_PRIMARY }; // "mimetype = ? AND deleted = ?" String selection = Data.MIMETYPE + " = ? AND " Phone.DELETED + " = ?"; String[] args = {Phone.CONTENT_ITEM_TYPE, "0"}; return new CursorLoader( this, Data.CONTENT_URI, projection, selection, args, null); 

任何想法为什么Phone.DELETED列不包含在光标中? 文件确实说 –

来自关联的原始联系人的某些列也可以通过隐式联接来使用。

Related of "隐式连接列如何与Android联系人数据配合使用?"

看起来您已经find了许多地方已经logging的function,但尚未实现。 我打开了一个跟踪这个问题的错误 – 让我们看看AOSP的人对这个问题有什么要说的( bug报告 )。

同时,您可以使用以下解决方法:

 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); 

变化:

  1. 使用RawContactsEntity的 URI
  2. LOOKUP_KEY无法通过上述URI访问 – 如果您LOOKUP_KEY需要此列,则必须执行附加查询
  3. 如果要在CursorAdapter使用生成的Cursor ,则需要_ID列。

编辑:以下@ MichaelAlanHuff的请求我发布这个答案是基于的代码部分

来自com.android.providers.contacts.ContactsProvider2#queryLocal() ( 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; } 

如您所见, SQLiteQueryBuilder用于构build查询的另外两个方法可以更改: setTablesAndProjectionMapForData()和其他query()方法。

com.android.providers.contacts.ContactsProvider2#setTablesAndProjectionMapForData()来源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); } 

在这里你可以看到使用StringBuilder的最后一个查询的table参数的构造,该构造函数被传递给几个append*()方法。 我不会发布他们的源代码,但他们真的join了方法名称中出现的表格。 如果rawContacts表将被join,我希望看到一个像appendRawContactJoin()这样的调用…

为了完整:我提到的另一个query()方法不会修改table参数:

 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; } 

对上述方法链的检查使我得出的结论是,有一个正式logging的function没有实施。