Android:使用 CursorLoader 加载联系人,而不是全部加载

Posted

技术标签:

【中文标题】Android:使用 CursorLoader 加载联系人,而不是全部加载【英文标题】:Android: loading contacts with CursorLoader, not all being loaded 【发布时间】:2015-03-24 06:04:06 【问题描述】:

我的 android 应用程序应该加载设备中记录的所有联系人并将它们显示在列表中。我无法弄清楚原因,但并非所有联系人都已加载。

这是我用来通过 CursorLoader 启动查询的代码:

public android.support.v4.content.Loader<Cursor> onCreateLoader(int id, Bundle args) 

        if (id == ContactsQuery.QUERY_ID) 
            Uri contentUri;


            if (mSearchTerm == null) 
                contentUri = ContactsQuery.CONTENT_URI;
             else 
                contentUri =
              Uri.withAppendedPath(ContactsQuery.FILTER_URI, Uri.encode(mSearchTerm));
        

        return new CursorLoader(getActivity(),
                contentUri,
                ContactsQuery.PROJECTION,
                ContactsQuery.SELECTION,
                null,
                ContactsQuery.SORT_ORDER);

ContactsQuery 定义如下:

public interface ContactsQuery 

    final static int QUERY_ID = 1;

    final static Uri CONTENT_URI = Contacts.CONTENT_URI;

    final static Uri FILTER_URI = Contacts.CONTENT_FILTER_URI;

    @SuppressLint("InlinedApi")
    final static String SELECTION =
            (Utils.hasHoneycomb() ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME) +
            "<>''" + " AND " + Contacts.IN_VISIBLE_GROUP + "=1";

    @SuppressLint("InlinedApi")
    final static String SORT_ORDER =
            Utils.hasHoneycomb() ? Contacts.SORT_KEY_PRIMARY : Contacts.DISPLAY_NAME;

    @SuppressLint("InlinedApi")
    final static String[] PROJECTION = 

            // The contact's row id
            Contacts._ID,

            Contacts.LOOKUP_KEY,

            Utils.hasHoneycomb() ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME,

            Utils.hasHoneycomb() ? Contacts.PHOTO_THUMBNAIL_URI : Contacts._ID,

            SORT_ORDER,
    ;

    final static int ID = 0;
    final static int LOOKUP_KEY = 1;
    final static int DISPLAY_NAME = 2;
    final static int PHOTO_THUMBNAIL_DATA = 3;
    final static int SORT_KEY = 4;

为什么当 mSearchTerm 为空时没有加载所有联系人?

【问题讨论】:

【参考方案1】:

您只是下拉手机联系人的内容 - 存储在 SIM 卡上的联系人可能因手机设置而无法访问(例如,如果手机禁止访问 SIM 卡联系人)。

Here is a post 将向您展示如何分别阅读它们。

您可以使用以下方法来辨别两者:

//for SIM Card 
ContentValues values = new ContentValues();
values.put(RawContacts.ACCOUNT_TYPE, "com.android.contacts.sim");
values.put(RawContacts.ACCOUNT_NAME, "SIM");
Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values);

//for everyone else
values.clear();
values.put(Data.RAW_CONTACT_ID, rawContactId);
values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
values.put(StructuredName.DISPLAY_NAME, "Name");

【讨论】:

那么SIM联系人表有完全不同的列? 是的 - 有几个原因。首先,可用于在 SIM 卡上存储联系人信息的存储空间和字段更少,其次它们存储在两个不同的位置。您仍然可以使用游标来加载它们,但它们使用不同的 URI 并具有不同的列名。但不要忘记,不同的手机会有不同的行为(有些手机会以您尝试获取它们的方式为您提供手机和 SIM 卡联系人,而其他手机则不会)。这只是 Android 编程的乐趣之一。 我不认为有一个很好的方法来判断 SIM 卡联系人是否以通常的方式加载? 用潜在的解决方案更新了我的答案,以确定它们的来源。不过,它仍然需要两次调用。 谢谢。我正在考虑拥有两个查询 ID,并在通常的加载完成后启动 SIM 加载。看看这是否有效。【参考方案2】:

问题出在选择上。违规行是

final static String SELECTION =
        (Utils.hasHoneycomb() ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME) +
        "<>''" + " AND " + Contacts.IN_VISIBLE_GROUP + "=1";

丢失的联系人有 Contacts.IN_VISIBLE_GROUP 1。这种行为似乎有点病态,因为在内置应用程序的联系人列表中显示的完全有效的联系人(例如我的母亲)似乎不可见团体。我实现了一个 kludge:

final static String SELECTION =
            (Utils.hasHoneycomb() ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME) +
            "<>'' AND ("+Contacts.HAS_PHONE_NUMBER+"=1 OR "+Contacts.IN_VISIBLE_GROUP+" = 1)";

这对我的应用程序来说已经足够了。

【讨论】:

以上是关于Android:使用 CursorLoader 加载联系人,而不是全部加载的主要内容,如果未能解决你的问题,请参考以下文章

android studio中的cursorLoader

Android:CursorLoader 在非最顶层 Fragment 上崩溃

Xamarin Android,使用带有选择和选择参数的 CursorLoader 获取联系人手机号码

安卓:CursorLoader、LoaderManager、SQLite

没有 ContentProvider 的 CursorLoader 使用

SQLite 异常错误,使用 CursorLoader 和 ContactContracts