在 Adapter 或 Fragment 中为 ContactsContract 设置数据的 MIMETYPE

Posted

技术标签:

【中文标题】在 Adapter 或 Fragment 中为 ContactsContract 设置数据的 MIMETYPE【英文标题】:Setting MIMETYPE of Data for ContactsContract in Adapter or Fragment 【发布时间】:2018-08-10 06:57:24 【问题描述】:

在我的应用程序中,我希望显示

的联系方式
ContactsContract.CommonDataKinds.Organization.TITLE

在 ContactsContract 中,MIMETYPE 用于选择手机中大部分有用数据的列的标识。

我正在寻求在我的列表视图中显示联系人的职位。我在 WHERE/SELECTION 子句中使用了 IN 的 SQL 注入,代码如下。

 private static final String SELECTION =
            ContactsContract.RawContactsEntity.MIMETYPE + " IN ('" +
            ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE + "')";

这是可行的,因为它在 where 子句中删除了此处没有值的项目,这在很大程度上减少了列表中的项目数量。

如上所述,我正在寻找如何在我的 CursorLoader 或我的 CursorAdapter 中设置光标的 MIMETYPE。

绑定适配器方法如下所示

public void onBindViewHolder(ContactsViewHolder viewHolder, Cursor cursor) 
    String profession = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE));
    String contactID = cursor.getString(cursor.getColumnIndex( ContactsContract.Data.CONTACT_ID));
    Uri contactURI = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,
            Integer.parseInt(contactID));
    viewHolder.setProfession(profession);
    viewHolder.setURI(contactURI);

CursorLoader 看起来像这样。 FROM_COLUMNS 包含基本数据,包括

 ContactsContract.CommonDataKinds.Organization.TITLE


 return new CursorLoader(
                        getContext(),
                        ContactsContract.Data.CONTENT_URI,
                        FROM_COLUMNS,
                        null,
                        null,
                        null
                );

【问题讨论】:

【参考方案1】:

您现在所做的基本上是在联系人数据库中显示所有职位的列表,并获取每个职位的联系人 ID。

如果我理解正确,您想要实现的是在数据库中显示所有联系人的列表,如果联系人包含职位,则将其显示在联系方式?

如果是这样,您不能在 Data.CONTENT_URI 上创建 CursorLoader,因为它包含每个数据一项,即每个联系人可能包含许多数据行。

您可以完全避免使用 CursorLoader,并遍历 Data 中的所有项目 - 将它们存储在内存中的某个 HashMap 中,然后创建一个 ListView/RecyclerView 适配器以在屏幕上显示 HashMap。

下面是帮助您入门的代码(考虑创建一个自定义对象来包含联系信息,而不是我在下面使用的字符串列表):

Map<Long, List<String>> contacts = new HashMap<Long, List<String>>();

String[] projection = Data.CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1 ;
// select only contacts that have at least one phone, email or job
String selection = Data.MIMETYPE + " IN ('" + Phone.CONTENT_ITEM_TYPE + "', '" + Email.CONTENT_ITEM_TYPE + "', '" + Organization.CONTENT_ITEM_TYPE + "')";
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);

while (cur != null && cur.moveToNext()) 
    long id = cur.getLong(0);
    String name = cur.getString(1);
    String mime = cur.getString(2); // type of data: email / phone / company
    String data = cur.getString(3); // the actual info, e.g. +1-212-555-1234

    switch (mime) 
        case Phone.CONTENT_ITEM_TYPE: 
            kind = "phone"; 
            break;
        case Email.CONTENT_ITEM_TYPE: 
            kind = "email";
            break;
        case Organization.CONTENT_ITEM_TYPE: 
            kind = "job";
            break;
    

    Log.d(TAG, "got " + id + ", " + name + ", " + data);

    // add info to existing list if this contact-id was already found, or create a new list in case it's new
    List<String> infos;
    if (contacts.containsKey(id)) 
        infos = contacts.get(id);
     else 
        infos = new ArrayList<String>();
        infos.add("name = " + name);
        contacts.put(id, infos);
    
    infos.add(kind + "= " + data);

【讨论】:

感谢您的指导。使用 loader 的好处之一是增加了安全性,而且 Loader 内置了一个 ContentObserver,我也很喜欢。可能必须继续研究以挖掘最佳方法。这可能对某人有帮助 gist.github.com/piyush-malaviya/… 不确定安全优势是什么,但 contentObserver 应该很容易添加 我认为核心问题在于选择子句,因为我不仅要检索有专业的项目,还要检索没有专业的项目。这里有什么线索吗? MIMETYPE IN (...) 是 OR 选择,因此您应该获取所有联系人(没有电话、电子邮件或组织的联系人除外) 我使用了 Map 方法和自定义对象,并且取得了不错的进展。

以上是关于在 Adapter 或 Fragment 中为 ContactsContract 设置数据的 MIMETYPE的主要内容,如果未能解决你的问题,请参考以下文章

在 Fragment 中使用 Spinner 和 Adapter

Fragment的Adapter和新的Fragment如何建立通信?

从 Adapter 向 Fragment 发送数据并在 Fragment 中获取

为啥 recyclerview$adapter 在片段中为空

cathome 猫家 开发日记-tablayout+viewpager+fragment

如何从 RecyclerView.Adapter<CardAdapter.ViewHolder> 打开片段