获取Android中的所有联系数据 - 多个URI



我正在一个人获取所有联系数据。我需要 :* 名* 姓* 电话号码* 版本等。

为此,我正在对整个联系人进行查询,然后,对于每个联系人ID,我都会获取相关数据。

问题在于,大约400个接触时间需要大量时间,超过10秒。(在三星I9300上以4.4.2运行)

我不需要向用户显示任何内容,我只是在后台将联系人同步到我的服务器,所以我没有任何UI问题...只是迭代联系人,查看需要更新并将其添加到我的arraylist中,然后将其发布到服务器。

public static void getAllContactsFromDevice() {
        long startTime = System.currentTimeMillis();
        Log.d(TAG, "startTime: " + startTime);
        //  Get all contacts by cursor
        ContentResolver cr = getContext().getContentResolver();
        Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null,
                null, null, null);
        if (cursor.moveToFirst() && cursor.getCount() > 0) {
            while (cursor.isAfterLast() == false) {
                // get contact id on the device DB.
                String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
                String contactNumber = null;
                //  Get all phone numbers.
                Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, null, null);
                // if the user has numbers
                // get just the first one for now
                if (phones.moveToNext())
                    contactNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                // close the cursor to prevent leak
                phones.close();
                // if we dont have a phone number, continue to next contact.
                if (contactNumber == null) {
                    cursor.moveToNext();
                    continue;
                }
                // get first and last name by contact id
                String[] projection = new String[]{ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME};
                String where = ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?";
                String[] whereParameters = new String[]{contactId, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE};
                Cursor nameCur = cr.query(ContactsContract.Data.CONTENT_URI, projection, where, whereParameters, null);
                String given = null;
                String family = null;
                try {
                    if (nameCur.getCount() > 0) {
                        nameCur.moveToFirst();
                        given = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
                        family = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
                        nameCur.close();
                    }
                    // if there is no name, continue to next contact.
                    else {
                        nameCur.close();
                        cursor.moveToNext();
                        continue;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    nameCur.close();
                }

                if (given == null || given == "null")
                    given = "";
                if (family == null || family == "null")
                    family = "";
                String[] mProjection = new String[]{ContactsContract.RawContacts.VERSION};
                String[] mWhereParameters = new String[]{contactId};
                String mWhere = ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ? ";
                Cursor mCursor = cr.query(ContactsContract.RawContacts.CONTENT_URI, mProjection, mWhere, mWhereParameters, null);
                int contactVersion = 0;
                try {
                    if (mCursor.getCount() > 0) {
                        mCursor.moveToFirst();
                        contactVersion = mCursor.getInt(mCursor.getColumnIndex(ContactsContract.RawContacts.VERSION));
                        mCursor.close();
                    } else {
                        mCursor.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    mCursor.close();
                }
                cursor.moveToNext();
            }
        }
        cursor.close();
        long endTime = System.currentTimeMillis();
        Log.d(TAG, "endTime: " + endTime);
        Log.d(TAG, "total time: " + (endTime - startTime));
    }

总时间:18280 ms

我在这里查看了developer.android.com,但没有发现任何有用的东西。

此答案也没有多大帮助。

问题是,对于每个联系人,您都会执行一些查询:到电话号码表,到结构化名称表等。单个查询到电话号码列表等

在带有约400个触点的Genymotion上,该方法可使30倍更好的性能(从2.8到100ms)。这是我使用的代码:

private static <TLeft, TRight> Function<Pair<TLeft, TRight>, TLeft> getExtractLeftFunction() {
  return new Function<Pair<TLeft, TRight>, TLeft>() {
    @Override
    public TLeft apply(Pair<TLeft, TRight> input) {
      return input.first;
    }
  };
}
private static <TLeft, TRight> Map<TLeft, TRight> toMap(Iterable<Pair<TLeft, TRight>> pairs) {
  Map<TLeft, TRight> result = Maps.newHashMap();
  for (Pair<TLeft, TRight> pair : pairs) {
    result.put(pair.first, pair.second);
  }
  return result;
}
private static class Name {
  public final String mGivenName;
  public final String mFamilyName;
  private Name(String givenName, String familyName) {
    mGivenName = givenName;
    mFamilyName = familyName;
  }
}
public void getAllContactsFromDevice() {
  long startTime = System.currentTimeMillis();
  Log.d(TAG, "startTime: " + startTime);
  //  Get all contacts by cursor
  ContentResolver cr = getContentResolver();
  ImmutableList<Long> contactIds = ProviderAction
      .query(Contacts.CONTENT_URI)
      .projection(Contacts._ID)
      .perform(getContentResolver())
      .toFluentIterable(SingleRowTransforms.getColumn(Contacts._ID).asLong())
      .toImmutableList();
  Map<Long, String> phonesMap = toMap(
      ProviderAction.query(Phone.CONTENT_URI)
          .projection(
              Phone.CONTACT_ID,
              Phone.NUMBER
          )
          .whereIn(Phone.CONTACT_ID, contactIds)
          .perform(getContentResolver())
          .toFluentIterable(getToPairFunction(
              SingleRowTransforms.getColumn(Phone.CONTACT_ID).asLong(),
              SingleRowTransforms.getColumn(Phone.NUMBER).asString())
          )
  );
  Map<Long, String> contactsWithPhones = Maps.filterValues(phonesMap, Predicates.notNull());
  Map<Long, Name> contactNamesMap = toMap(ProviderAction
      .query(Data.CONTENT_URI)
      .projection(
          StructuredName.CONTACT_ID,
          StructuredName.FAMILY_NAME,
          StructuredName.GIVEN_NAME
      )
      .whereIn(StructuredName.CONTACT_ID, contactsWithPhones.keySet())
      .perform(getContentResolver())
      .toFluentIterable(getToPairFunction(
          SingleRowTransforms.getColumn(Phone.CONTACT_ID).asLong(),
          new Function<Cursor, Name>() {
            private Function<Cursor, String> mFamilyNameGetter = SingleRowTransforms.getColumn(StructuredName.FAMILY_NAME).asString();
            private Function<Cursor, String> mGivenNameGetter = SingleRowTransforms.getColumn(StructuredName.GIVEN_NAME).asString();
            @Override
            public Name apply(Cursor input) {
              return new Name(
                  mGivenNameGetter.apply(input),
                  mFamilyNameGetter.apply(input)
              );
            }
          }
      ))
  );
  Map<Long, Integer> versions = toMap(ProviderAction.query(RawContacts.CONTENT_URI)
      .projection(
          StructuredName.CONTACT_ID,
          RawContacts.VERSION
      )
      .whereIn(StructuredName.CONTACT_ID, contactNamesMap.keySet())
      .perform(getContentResolver())
      .toFluentIterable(getToPairFunction(
          SingleRowTransforms.getColumn(StructuredName.CONTACT_ID).asLong(),
          SingleRowTransforms.getColumn(RawContacts.VERSION).asInteger())
      )
  );
  long endTime = System.currentTimeMillis();
  Log.d(TAG, "endTime: " + endTime);
  Log.d(TAG, "total time: " + (endTime - startTime));
}

我正在使用android-db-commons(免责声明:我是合着者)来执行所有查询并处理输出。该库不支持将查询结果放入地图中(现在!),这是您想在这里做的,因此上述代码有点混乱,但是它仍然击败了杂耍多个光标IMO。

最新更新