我正在一个人获取所有联系数据。我需要 :* 名* 姓* 电话号码* 版本等。
为此,我正在对整个联系人进行查询,然后,对于每个联系人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。