public class ContactLoaderReceiver extends BroadcastReceiver {
private ContactLoader mLoader;
public ContactLoaderReceiver(ContactLoader mLoader) {
this.mLoader = mLoader;
/**
* Register for events related toapplication installs/removals/updates.
*/
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
mLoader.getContext().registerReceiver(this, filter);
/**
* Register for events related to sdcard installation.
*/
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mLoader.getContext().registerReceiver(this, sdFilter);
}
/**
* This method is called when the BroadcastReceiver is receiving an Intent
* broadcast. During this time you can use the other methods on
* BroadcastReceiver to view/modify the current result values. This method
* is always called within the main thread ofits process, unless you
* explicitly asked foritto be scheduled on a different thread using
* thread you should
* never perform long-running operations init (there is a timeoutof
* 10 seconds thatthe system allows beforeconsideringthe receiver to
* be blocked and a candidate to be killed). You cannot launch a popup dialog
* in your implementation of onReceive().
* <p/>
* <p><b>If this BroadcastReceiver was launched through a <receiver> tag,
* thenthe object is no longer alive afterreturningfrom this
* function.</b> This means you should not perform any operations that
* return a resultto you asynchronously -- in particular, for interacting
* with services, you should use
* {@link android.content.Context#startService(android.content.Intent)} instead of
* to interact with a service thatis already running, you can use
* {@link #peekService}.
* <p/>
* <p>The Intent filters used in {@link android.content.Context#registerReceiver}
* andinapplication manifests are <em>not</em> guaranteed to be exclusive. They
* are hints tothe operating system about how to find suitable recipients. It is
* possible for senders to force delivery to specific recipients, bypassing filter
* resolution. For this reason, {@link #onReceive(android.content.Context, android.content.Intent) onReceive()}
* implementations should respond only to known actions, ignoring any unexpected
* Intents that they may receive.
*
* @param context The Context in which the receiver isrunning.
* @param intent The Intent being received.
*/
@Override
public void onReceive(Context context, Intent intent) {
/**
* Tell the loader aboutthe change.
*/
mLoader.onContentChanged();
}
}
联系人Loader(ContactLoader)
public classContactLoaderextendsAsyncTaskLoader<LinkedList<ContactInfo>> {/**
* 获取库Phone表字段 *
*/private static final String[] PHONES_PROJECTION = new String[]{
Phone.DISPLAY_NAME, Phone.NUMBER, Photo.PHOTO_ID, Phone.CONTACT_ID};
/**
* 联系人显示名称 *
*/private static final int PHONES_DISPLAY_NAME_INDEX = 0;
/**
* 电话号码 *
*/private static final int PHONES_NUMBER_INDEX = 1;
private Context context;
private ContactLoaderReceiver receiver;
public ContactLoader(Context context) {
super(context);
this.context = context;
}
/**
* Called on a worker thread to perform the actual load and to return
* the result of the load operation.
* <p/>
* Implementations should not deliver the result directly, but should return them
* from this method, which will eventually end up calling {@link #deliverResult} on
* the UI thread. If implementations need to process the results on the UI thread
* they may override {@link #deliverResult} and do so there.
* <p/>
* To support cancellation, this method should periodically check the value of
* <p/>
* When the load is canceled, this method may either return normally or throw
* call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
* result object, if any.
*
* @return The result of the load operation.
* @see #onCanceled
*/@Override
public LinkedList<ContactInfo> loadInBackground() {
returnthis.getPhoneContacts(this.context);
}
/**
* 得到手机通讯录联系人信息 *
*/private LinkedList<ContactInfo> getPhoneContacts(Context context) {
LinkedList<ContactInfo> mContacts = new LinkedList<>();
ContentResolver resolver = context.getContentResolver();
// 获取手机联系人
Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,
ContactLoader.PHONES_PROJECTION, null, null, null);
if (phoneCursor != null) {
while (phoneCursor.moveToNext()) {
String phoneNumber = phoneCursor
.getString(ContactLoader.PHONES_NUMBER_INDEX);
if (TextUtils.isEmpty(phoneNumber)) {
continue;
}
String contactName = phoneCursor
.getString(ContactLoader.PHONES_DISPLAY_NAME_INDEX);
String pinyin = "" + CharacterParser.getInstance().getSelling(contactName);
String pinyin_tag;
if (!TextUtils.isEmpty(pinyin)) {
pinyin_tag = pinyin.substring(0, 1).toUpperCase();
} else {
pinyin_tag = "#";
}
mContacts.add(new ContactInfo(contactName, StringUtil.filterPhoneNumber(phoneNumber), pinyin_tag, pinyin));
}
phoneCursor.close();
}
/**
* 排序
*/
Collections.sort(mContacts, new Comparator<ContactInfo>() {
@Override
public int compare(ContactInfo lhs, ContactInfo rhs) {
if ("#".equals(lhs.getPinyinTag())) {
if (!"#".equals(rhs.getPinyinTag())) {
return1;
}
} else {
if ("#".equals(rhs.getPinyinTag())) {
return -1;
}
}
if (TextUtils.isEmpty(lhs.getPinyin())) {
return -1;
}
if (TextUtils.isEmpty(rhs.getPinyin())) {
return1;
}
String l = lhs.getPinyin();
String r = rhs.getPinyin();
return l.compareTo(r);
}
});
return mContacts;
}
@Overrideprotected void onStartLoading() {
super.onStartLoading();
if (this.receiver == null) {
this.receiver = new ContactLoaderReceiver(this);
}
forceLoad();
}
@Override
public void onCanceled(LinkedList<ContactInfo> data) {
super.onCanceled(data);
}
@Overrideprotected void onReset() {
// Ensure the loader is stopped
onStopLoading();
// The Loader is being reset, so we should stop monitoring for changes.if (this.receiver != null) {
this.getContext().unregisterReceiver(this.receiver);
this.receiver = null;
}
}
@Overrideprotected void onStopLoading() {
cancelLoad();
}
}