隐式联接列如何与Android联系人数据一起使用? [英] How do implicit joined columns work with Android contacts data?

查看:67
本文介绍了隐式联接列如何与Android联系人数据一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在查询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);

更改:

  1. 使用 RawContactsEntity的 URI
  2. LOOKUP_KEY无法通过上述URI访问-如果您绝对需要此列,则必须执行其他查询
  3. 如果要在CursorAdapter中使用生成的Cursor,则需要
  4. _ID列.
  1. Use RawContactsEntity's URI
  2. LOOKUP_KEY is not accessible via above URI - you'll have to execute additional query if you absolutely need this column
  3. _ID column will be required if you are going to use the resulting Cursor in CursorAdapter.

按照@MichaelAlanHuff的要求,我要发布此答案基于的代码部分

来自com.android.providers.contacts.ContactsProvider2#queryLocal()(

如您所见,还有两种其他方法,其中 SQLiteQueryBuilder 可以更改:setTablesAndProjectionMapForData()和其他query()方法.

As you can see, there are two additional methods where SQLiteQueryBuilder used to build the query could be changed: 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()之类的调用...

Here you see the construction of 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参数:

For completeness: the other 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;
}

对上述方法链的检查得出的结论是,有一个正式记录的功能尚未实现.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆