我开发的应用程序需要从电话簿中获取所有联系人。联系人案例:Viber,WhatsApp,Telegram。我找到了一个很好的解决方案RxContacts library。但这种变化并没有给我电话簿中的所有联系人。 This is我与作者讨论了这个问题。
如何从服务电话簿中获取所有可用的联系人?
RxContacts
.fetch(context)
.filter(contact -> contact.inVisibleGroup == 1)
.filter(contact -> !contact.phoneNumbers.isEmpty())
.filter(contact -> contact.phoneNumber.contains(mPhoneField) || contact.displayName.toLowerCase().contains(mPhoneField.toLowerCase()))
.toSortedList((lhs, rhs) -> lhs.displayName.compareToIgnoreCase(rhs.displayName))
.compose(RxUtils.async())
.doOnSubscribe(this::showLoading)
.compose(mRxLoaderManager.restart(CONTACTS_LOADER))
.subscribe(this::handleResponse, this::handleContactsError, this::onCompleted);
RxContacts
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.util.LongSparseArray;
import com.elegion.friendlypay.model.rxContacts.Contact;
import rx.Observable;
import rx.Subscriber;
import static com.elegion.friendlypay.rxcontacts.ColumnMapper.mapDisplayName;
import static com.elegion.friendlypay.rxcontacts.ColumnMapper.mapEmail;
import static com.elegion.friendlypay.rxcontacts.ColumnMapper.mapInVisibleGroup;
import static com.elegion.friendlypay.rxcontacts.ColumnMapper.mapPhoneNumber;
import static com.elegion.friendlypay.rxcontacts.ColumnMapper.mapPhoneNumberSingle;
import static com.elegion.friendlypay.rxcontacts.ColumnMapper.mapPhoto;
import static com.elegion.friendlypay.rxcontacts.ColumnMapper.mapStarred;
import static com.elegion.friendlypay.rxcontacts.ColumnMapper.mapThumbnail;
public class RxContacts {
private static final String[] PROJECTION = {
ContactsContract.Data.CONTACT_ID,
ContactsContract.Data.DISPLAY_NAME_PRIMARY,
ContactsContract.Data.STARRED,
ContactsContract.Data.PHOTO_URI,
ContactsContract.Data.PHOTO_THUMBNAIL_URI,
ContactsContract.Data.DATA1,
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.IN_VISIBLE_GROUP
};
private ContentResolver resolver;
/**
* Fetches all contacts from the contacts apps and social networking apps.
* @param context The context.
* @return Observable that emits contacts on success.
*/
public static Observable<Contact> fetch (@NonNull final Context context) {
return Observable.create(new Observable.OnSubscribe<Contact>() {
@Override
public void call (Subscriber<? super Contact> subscriber) {
new RxContacts(context).fetch(subscriber);
}
});
}
private RxContacts (@NonNull Context context) {
resolver = context.getContentResolver();
}
private void fetch (Subscriber<? super Contact> subscriber) {
LongSparseArray<Contact> contacts = new LongSparseArray<>();
// Create a new cursor and go to the first position
Cursor cursor = createCursor();
cursor.moveToFirst();
// Get the column indexes
int idxId = cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID);
int idxInVisibleGroup = cursor.getColumnIndex(ContactsContract.Data.IN_VISIBLE_GROUP);
int idxDisplayNamePrimary = cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME_PRIMARY);
int idxStarred = cursor.getColumnIndex(ContactsContract.Data.STARRED);
int idxPhoto = cursor.getColumnIndex(ContactsContract.Data.PHOTO_URI);
int idxThumbnail = cursor.getColumnIndex(ContactsContract.Data.PHOTO_THUMBNAIL_URI);
int idxMimetype = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE);
int idxData1 = cursor.getColumnIndex(ContactsContract.Data.DATA1);
// Map the columns to the fields of the contact
while (!cursor.isAfterLast()) {
// Get the id and the contact for this id. The contact may be a null.
long id = cursor.getLong(idxId);
Contact contact = contacts.get(id, null);
if (contact == null) {
// Create a new contact
contact = new Contact(id);
// Map the non collection attributes
mapInVisibleGroup(cursor, contact, idxInVisibleGroup);
mapDisplayName(cursor, contact, idxDisplayNamePrimary);
mapStarred(cursor, contact, idxStarred);
mapPhoto(cursor, contact, idxPhoto);
mapThumbnail(cursor, contact, idxThumbnail);
// Add the contact to the collection
contacts.put(id, contact);
} else {
String mimetype = cursor.getString(idxMimetype);
switch (mimetype) {
case ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE: {
mapEmail(cursor, contact, idxData1);
break;
}
case ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE: {
mapPhoneNumber(cursor, contact, idxData1);
//while (contact.phoneNumbers.iterator().hasNext())
mapPhoneNumberSingle(cursor, contact, idxData1);
break;
}
}
}
cursor.moveToNext();
}
// Close the cursor
cursor.close();
// Emit the contacts
for (int i = 0; i < contacts.size(); i++) {
subscriber.onNext(contacts.valueAt(i));
}
subscriber.onCompleted();
}
private Cursor createCursor () {
return resolver.query(
ContactsContract.Data.CONTENT_URI,
PROJECTION,
null,
null,
ContactsContract.Data.CONTACT_ID
);
}
}
ColumnMapper
class ColumnMapper {
// Utility class -> No instances allowed
private ColumnMapper () {}
static void mapInVisibleGroup (Cursor cursor, Contact contact, int columnIndex) {
contact.inVisibleGroup = cursor.getInt(columnIndex);
}
static void mapDisplayName (Cursor cursor, Contact contact, int columnIndex) {
String displayName = cursor.getString(columnIndex);
if (displayName != null && !displayName.isEmpty()) {
contact.displayName = displayName;
}
}
static void mapEmail (Cursor cursor, Contact contact, int columnIndex) {
String email = cursor.getString(columnIndex);
if (email != null && !email.isEmpty()) {
contact.emails.add(email);
}
}
static void mapPhoneNumber (Cursor cursor, Contact contact, int columnIndex) {
String phoneNumber = cursor.getString(columnIndex);
if (phoneNumber != null && !phoneNumber.isEmpty() && ValidationPhoneUtil.isValidPhone(phoneNumber)) {
// Remove all whitespaces
phoneNumber = phoneNumber.replaceAll("\\s+","");
contact.phoneNumbers.add(phoneNumber);
}
}
static void mapPhoneNumberSingle (Cursor cursor, Contact contact, int columnIndex) {
String phoneNumber = cursor.getString(columnIndex);
if (phoneNumber != null && !phoneNumber.isEmpty() && ValidationPhoneUtil.isValidPhone(phoneNumber)) {
// Remove all whitespaces
phoneNumber = phoneNumber.replaceAll("\\s+","");
contact.phoneNumber += phoneNumber + "\n";
}
}
static void mapPhoto (Cursor cursor, Contact contact, int columnIndex) {
String uri = cursor.getString(columnIndex);
if (uri != null && !uri.isEmpty()) {
contact.photo = Uri.parse(uri);
}
}
static void mapStarred (Cursor cursor, Contact contact, int columnIndex) {
contact.starred = cursor.getInt(columnIndex) != 0;
}
static void mapThumbnail (Cursor cursor, Contact contact, int columnIndex) {
String uri = cursor.getString(columnIndex);
if (uri != null && !uri.isEmpty()) {
contact.thumbnail = Uri.parse(uri);
}
}
}
与
import android.net.Uri;
import java.util.HashSet;
import java.util.Set;
/**
* Contact entity.
* @author Ulrich Raab
*/
public class Contact {
/**
* The unique id of this contact.
*/
public final long id;
/**
* Flag indicating if this contact should be visible in any user interface.
*/
public int inVisibleGroup;
/**
* The display name of this contact.
*/
public String displayName;
/**
* Flag indicating if this contact is a favorite contact.
*/
public boolean starred;
/**
* The URI of the full-size photo of this contact.
*/
public Uri photo;
/**
* The URI of the thumbnail of the photo of this contact.
*/
public Uri thumbnail;
/**
* The email addresses of this contact.
*/
public Set<String> emails = new HashSet<>();
/**
* The phone numbers of this contact.
*/
public Set<String> phoneNumbers = new HashSet<>();
/**
* Creates a new contact with the specified id.
* @param id The id of the contact.
*/
Contact (long id) {
this.id = id;
}
@Override
public int hashCode () {
return (int) (id ^ (id >>> 32));
}
@Override
public boolean equals (Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Contact contact = (Contact) o;
return id == contact.id;
}
}
答案 0 :(得分:1)
尝试这个,可能对你有所帮助
https://commondatastorage.googleapis.com/androiddevelopers/shareables/training/ContactsList.zip
答案 1 :(得分:0)
似乎已在1.1.4版本中修复:https://github.com/UlrichRaab/rx-contacts/releases/tag/1.1.4
干杯