public class ImageBean implements Parcelable {
private String path = null;
private boolean isSeleted = false;
public ImageBean(String path, boolean selected) {
this.path = path;
this.isSeleted = selected;
}
public ImageBean() {
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(path);
dest.writeInt(isSeleted ? 1 : 0);
}
public static final Creator CREATOR = new Creator() {
@Override
public ImageBean createFromParcel(Parcel source) {
return new ImageBean(source.readString(), source.readInt() == 1 ? true : false);
}
@Override
public ImageBean[] newArray(int size) {
return new ImageBean[size];
}
};
/**
* @return the path
*/
public String getPath() {
return path;
}
/**
* @param path the path to set
*/
public void setPath(String path) {
this.path = path;
}
/**
* @return the isSeleted
*/
public boolean isSeleted() {
return isSeleted;
}
/**
* @param isSeleted the isSeleted to set
*/
public void setSeleted(boolean isSeleted) {
this.isSeleted = isSeleted;
}
}
public class ImagesLoader extends AsyncTaskLoader<ArrayList<ImageBean>> {
private ArrayList mImages = null;
/**
* @param context
*/
public ImagesLoader(Context context) {
super(context);
}
@Override
public ArrayList loadInBackground() {
ArrayList imageList = new ArrayList();
Cursor imageCursor = getContext().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID}, null, null, MediaStore.Images.Media._ID);
if (imageCursor != null && imageCursor.getCount() > 0) {
while (imageCursor.moveToNext()) {
ImageBean item = new ImageBean(imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA)), false);
imageList.add(item);
}
}
if (imageCursor != null) {
imageCursor.close();
}
// show newest photo at beginning of the list
Collections.reverse(imageList);
return imageList;
}
/* Runs on the UI thread */
@Override
public void deliverResult(ArrayList images) {
if (isReset()) {
// An async query came in while the loader is stopped
if (images != null) {
images.clear();
images = null;
}
return;
}
ArrayList oldImages = mImages;
mImages = images;
if (isStarted()) {
super.deliverResult(images);
}
if (oldImages != null && oldImages != mImages) {
oldImages.clear();
oldImages = null;
}
}
@Override
protected void onStartLoading() {
if (mImages != null && mImages.size() > 0) {
deliverResult(mImages);
}
if (takeContentChanged() || mImages == null) {
forceLoad();
}
}
/**
* Must be called from the UI thread
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
@Override
public void onCanceled(ArrayList images) {
if (images != null) {
images.clear();
images = null;
}
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mImages != null) {
mImages.clear();
mImages = null;
}
}
}
public class GalleryActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<ArrayList<ImageBean>> {
......
......
......
@Override
public Loader> onCreateLoader(int i, Bundle bundle) {
return new ImagesLoader(this);
}
@Override
public void onLoadFinished(Loader> loader, ArrayList images) {
this.mImages = images;
}
@Override
public void onLoaderReset(Loader> images) {
}
}
public class ContactInfo implements Serializable {
private String name;
private String phoneNumber;
private boolean selected;
private String pinyinTag;
private String pinyin;
public ContactInfo() {
}
public ContactInfo(String name, String phoneNumber, String pinyinTag, String pinyin) {
this.setName(name);
this.setPhoneNumber(phoneNumber);
this.setPinyinTag(pinyinTag);
this.setPinyin(pinyin);
}
public String getPinyin() {
return pinyin;
}
public void setPinyin(String pinyin) {
this.pinyin = pinyin;
}
public String getPinyinTag() {
return pinyinTag;
}
public void setPinyinTag(String pinyinTag) {
this.pinyinTag = pinyinTag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
public class ContactLoaderReceiver extends BroadcastReceiver {
private ContactLoader mLoader;
public ContactLoaderReceiver(ContactLoader mLoader) {
this.mLoader = mLoader;
/**
* Register for events related to application 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 of its process, unless you
* explicitly asked for it to be scheduled on a different thread using
* thread you should
* never perform long-running operations in it (there is a timeout of
* 10 seconds that the system allows before considering the receiver to
* be blocked and a candidate to be killed). You cannot launch a popup dialog
* in your implementation of onReceive().
*
* If this BroadcastReceiver was launched through a <receiver> tag,
* then the object is no longer alive after returning from this
* function. This means you should not perform any operations that
* return a result to 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 that is already running, you can use
* {@link #peekService}.
*
* The Intent filters used in {@link android.content.Context#registerReceiver}
* and in application manifests are not guaranteed to be exclusive. They
* are hints to the 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 is running.
* @param intent The Intent being received.
*/
@Override
public void onReceive(Context context, Intent intent) {
/**
* Tell the loader about the change.
*/
mLoader.onContentChanged();
}
}
public class ContactLoader extends AsyncTaskLoader<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.
*
* 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.
*
* To support cancellation, this method should periodically check the value of
*
* 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 loadInBackground() {
return this.getPhoneContacts(this.context);
}
/**
* 得到手机通讯录联系人信息 *
*/
private LinkedList getPhoneContacts(Context context) {
LinkedList 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() {
@Override
public int compare(ContactInfo lhs, ContactInfo rhs) {
if ("#".equals(lhs.getPinyinTag())) {
if (!"#".equals(rhs.getPinyinTag())) {
return 1;
}
} else {
if ("#".equals(rhs.getPinyinTag())) {
return -1;
}
}
if (TextUtils.isEmpty(lhs.getPinyin())) {
return -1;
}
if (TextUtils.isEmpty(rhs.getPinyin())) {
return 1;
}
String l = lhs.getPinyin();
String r = rhs.getPinyin();
return l.compareTo(r);
}
});
return mContacts;
}
@Override
protected void onStartLoading() {
super.onStartLoading();
if (this.receiver == null) {
this.receiver = new ContactLoaderReceiver(this);
}
forceLoad();
}
@Override
public void onCanceled(LinkedList data) {
super.onCanceled(data);
}
@Override
protected 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;
}
}
@Override
protected void onStopLoading() {
cancelLoad();
}
}
public class ImportContactActivity extends BaseActivity implements LoaderManager.LoaderCallbacks<LinkedList<ContactInfo>>{
......
......
......
@Override
public Loader> onCreateLoader(int i, Bundle bundle) {
return new ContactLoader(this);
}
@Override
public void onLoadFinished(Loader> linkedListLoader, LinkedList contactInfos) {
if (contactInfos != null && contactInfos.size() != 0) {
if (!this.load) {
this.contactList = contactInfos;
this.lvAdater.setList(this.contactList);
this.lvAdater.notifyDataSetChanged();
sideBar.setSections((String[]) lvAdater.getSections());
sideBar.invalidate();
this.load = true;
}
}
}
@Override
public void onLoaderReset(Loader> linkedListLoader) {
this.lvAdater.clearList();
}
}