隐式联接列如何与Android联系人数据一起使用? [英] How do implicit joined columns work with Android contacts data?
问题描述
我正在查询ContactsContract.Data
表以查找电话记录.
I'm querying the ContactsContract.Data
table to find phone records.
创建新的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
列不包含在光标中吗? 文档确实说-
Any idea why the Phone.DELETED
column isn't included in the cursor? The documentation does say -
关联原始联系人中的某些列也可用 通过隐式加入.
Some columns from the associated raw contact are also available through an implicit join.
推荐答案
好像您发现了一个功能,该功能已在许多地方进行了说明,但尚未实现.我打开了一个用于跟踪此问题的错误-让我们看看AOSP家伙在这个问题上要说些什么(
Looks like you've found a feature that has been documented in many places, but hadn't been implemented yet. I opened a bug for tracking this issue - lets see what AOSP guys have to say on the subject (bug report).
同时,您可以使用以下解决方法:
Meanwhile, you can use the following workaround:
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);
更改:
- 使用 RawContactsEntity的 URI
-
LOOKUP_KEY
无法通过上述URI访问-如果您绝对需要此列,则必须执行其他查询
如果要在 -
_ID
列.
CursorAdapter
中使用生成的Cursor
,则需要- Use RawContactsEntity's URI
LOOKUP_KEY
is not accessible via above URI - you'll have to execute additional query if you absolutely need this column_ID
column will be required if you are going to use the resultingCursor
inCursorAdapter
.
按照@MichaelAlanHuff的要求,我要发布此答案基于的代码部分
来自 如您所见,还有两种其他方法,其中 SQLiteQueryBuilder 用于构建查询的a>可以更改: As you can see, there are two additional methods where SQLiteQueryBuilder used to build the query could be changed: 在这里,您将看到使用 Here you see the construction of 出于完整性考虑:我提到的另一个 For completeness: the other 对上述方法链的检查得出的结论是,有一个正式记录的功能尚未实现. The inspection of the above chain of methods led me to the conclusion that there is an officially documented feature which is not implemented. 这篇关于隐式联接列如何与Android联系人数据一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!com.android.providers.contacts.ContactsProvider2#queryLocal()
(
setTablesAndProjectionMapForData()
和其他query()
方法.setTablesAndProjectionMapForData()
and additional query()
method.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
表,我希望在这里看到对appendRawContactJoin()
之类的调用... table
argument of the final query using StringBuilder
which is being passed to several append*()
methods. I'm not going to post their source code, but they really join
the tables that appear in methods' names. If rawContacts
table would be joined in, I'd expect to see a call to something like appendRawContactJoin()
here...query()
方法不会修改table
参数:query()
method that I mentioned does not modify table
argument: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;
}