这里主要用到了AsyncQueryHandler对象来查询手机图片资源,它内部是继承了Handler对象的.通过startQuery方法可以执行异步的查询.而如何使用ContentResolver的query方法的话,查询是在UI线程执行的,这样效果不太好,手机图片多的话,容易造成UI阻塞,通常如果采用这种方式的话,都会另起一个子线程来执行的,查询完毕在通过Handler发送消息来刷新UI,这种做法的话用起来感觉有点麻烦,因此采用AsyncQueryHandler将是一个不错的选择.
构造方法
需要传入ContentResolver
public AsyncQueryHandler(ContentResolver cr)
四个回调方法,回调方法是运行在UI线程的,可以放心的操作UI
个人感觉方法的注释也已经说的很清楚了,其实就是增、删、查、改的异步操作完成后会执行的回调.
/** 3. Called when an asynchronous query is completed. 4. 5. @param token the token to identify the query, passed in from 5. {@link #startQuery}. 6. @param cookie the cookie object passed in from {@link #startQuery}. 7. @param cursor The cursor holding the results from the query. */
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
// Empty
}
/** 8. Called when an asynchronous insert is completed. 9. 11. @param token the token to identify the query, passed in from 10. {@link #startInsert}. 11. @param cookie the cookie object that's passed in from 12. {@link #startInsert}. 13. @param uri the uri returned from the insert operation. */
protected void onInsertComplete(int token, Object cookie, Uri uri) {
// Empty
}
/** 14. Called when an asynchronous update is completed. 15. 18. @param token the token to identify the query, passed in from 16. {@link #startUpdate}. 17. @param cookie the cookie object that's passed in from 18. {@link #startUpdate}. 19. @param result the result returned from the update operation */
protected void onUpdateComplete(int token, Object cookie, int result) {
// Empty
}
/** 20. Called when an asynchronous delete is completed. 21. 25. @param token the token to identify the query, passed in from 22. {@link #startDelete}. 23. @param cookie the cookie object that's passed in from 24. {@link #startDelete}. 25. @param result the result returned from the delete operation */
protected void onDeleteComplete(int token, Object cookie, int result) {
// Empty
}
//增加
public final void startInsert(int token, Object cookie, Uri uri,
ContentValues initialValues)
//查询
public void startQuery(int token, Object cookie, Uri uri,
String[] projection, String selection, String[] selectionArgs,
String orderBy) {
//更新
public final void startUpdate(int token, Object cookie, Uri uri,
ContentValues values, String selection, String[] selectionArgs)
//删除
public final void startDelete(int token, Object cookie, Uri uri,
String selection, String[] selectionArgs) {
这里主要解释下token和cookie这2个参数的含义,这2个分别代表Message里面的what和obj属性,由此可见AsyncQueryHandler内部确实是通过Handler和Message来工作的.以下这段源码就很直观的体现了这点.
protected class WorkerHandler extends Handler {
public WorkerHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
final ContentResolver resolver = mResolver.get();
if (resolver == null) return;
WorkerArgs args = (WorkerArgs) msg.obj;
int token = msg.what;
int event = msg.arg1;
switch (event) {
case EVENT_ARG_QUERY:
Cursor cursor;
try {
cursor = resolver.query(args.uri, args.projection,
args.selection, args.selectionArgs,
args.orderBy);
// Calling getCount() causes the cursor window to be filled,
// which will make the first access on the main thread a lot faster.
if (cursor != null) {
cursor.getCount();
}
} catch (Exception e) {
Log.w(TAG, "Exception thrown during handling EVENT_ARG_QUERY", e);
cursor = null;
}
args.result = cursor;
break;
case EVENT_ARG_INSERT:
args.result = resolver.insert(args.uri, args.values);
break;
case EVENT_ARG_UPDATE:
args.result = resolver.update(args.uri, args.values, args.selection,
args.selectionArgs);
break;
case EVENT_ARG_DELETE:
args.result = resolver.delete(args.uri, args.selection, args.selectionArgs);
break;
}
// passing the original token value back to the caller
// on top of the event values in arg1.
Message reply = args.handler.obtainMessage(token);
reply.obj = args;
reply.arg1 = msg.arg1;
if (localLOGV) {
Log.d(TAG, "WorkerHandler.handleMsg: msg.arg1=" + msg.arg1
+ ", reply.what=" + reply.what);
}
reply.sendToTarget();
}
}
好了,介绍完AsyncQueryHandler,直接上demo吧.文章最下边有下载地址.
用于展示相册列表
/** * 展示相册 */
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private List<AlbumBean> mAlbumBeanList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setBackgroundDrawable(new ColorDrawable(Color.WHITE));
mListView = new ListView(this);
mListView.setCacheColorHint(Color.TRANSPARENT);
mListView.setSelector(new ColorDrawable());
setContentView(mListView);
queryAlbum();
initListener();
}
/** * 查询相片 */
private void queryAlbum() {
AsyncQueryHandler queryHandler = new AsyncQueryHandler(getContentResolver()) {
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
//查询结束时回调,这里回调的时候是UI线程
mAlbumBeanList = AlbumBean.parserList(cursor);
AlbumAdapter adapter = new AlbumAdapter(MainActivity.this, mAlbumBeanList);
mListView.setAdapter(adapter);
}
};
int token = 0; //相当于message的what
Object cookie = null;//相当于message的obj
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;//查询的uri
String[] projection = new String[]{ //查询的列
MediaStore.Images.Media._ID, //如果要使用CursorAdapter,那么就必须查询此字段
MediaStore.Images.Media.DATA //相片的路径
};
String selection = MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?";//查询的条件
String[] selectionArgs = new String[]{ //查询条件?号后面的参数
"image/jpeg", "image/png"
};
String orderBy = MediaStore.Images.Media.DATE_MODIFIED + " DESC";//根据修改日期降序排序
// 这个方法会运行在子线程
queryHandler.startQuery(token, cookie, uri, projection, selection, selectionArgs, orderBy);
}
/** * 初始化监听 */
private void initListener() {
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
AlbumBean albumBean = mAlbumBeanList.get(position);
Intent intent = new Intent(MainActivity.this, PhotoListActivity.class);
Bundle bundle = new Bundle();
if (position == 0) {
//当前点击的是所有相册
bundle.putStringArrayList("photoList", (ArrayList<String>) albumBean.allPhotoList);
} else {
//点击的是其他相册
bundle.putStringArrayList("photoList", (ArrayList<String>) albumBean.albumPhotoList);
}
intent.putExtras(bundle);
startActivity(intent);
}
});
}
}
用于展示具体的某个相册
/**具体的某个相册 * Created by mChenys on 2016/1/24. */
public class PhotoListActivity extends Activity {
private GridView mGridView;
private List<String> mPhotoList;
private BitmapUtils mBitmapUtils;
private int mWidth, mHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initData();
initView();
showPhotoList();
initListener();
}
private void initListener() {
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(PhotoListActivity.this, PhotoViewActivity.class);
intent.putExtra("photo", mPhotoList.get(position));
startActivity(intent);
}
});
}
private void initData() {
Intent intent = getIntent();
if (null != intent) {
Bundle bundle = intent.getExtras();
if (null != bundle) {
mPhotoList = bundle.getStringArrayList("photoList");
System.out.println("mPhotoList:" + mPhotoList);
}
}
mBitmapUtils = new BitmapUtils(this);
mBitmapUtils.configDefaultLoadingImage(R.drawable.app_default);
mWidth = (int) ((SizeUtils.getStreenWidth(this) - 2 * SizeUtils.px2dp(this, 1)) / 3.0f);
mHeight = mWidth;
System.out.println("mWidth:" + mWidth + " mHeight:" + mHeight + " SizeUtils.getStreenWidth(this):" +
SizeUtils.getStreenWidth(this));
}
private void initView() {
mGridView = new GridView(this);
mGridView.setNumColumns(3);
mGridView.setVerticalSpacing(SizeUtils.px2dp(this, 1));
mGridView.setHorizontalSpacing(SizeUtils.px2dp(this, 1));
mGridView.setCacheColorHint(Color.TRANSPARENT);
mGridView.setBackgroundColor(Color.parseColor("#262424"));
mGridView.setSelector(new ColorDrawable());
setContentView(mGridView);
}
private void showPhotoList() {
mGridView.setAdapter(new BaseAdapter() {
@Override
public int getCount() {
return mPhotoList == null ? 0 : mPhotoList.size();
}
@Override
public String getItem(int position) {
return mPhotoList == null ? "" : mPhotoList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
ImageView imageView = new ImageView(PhotoListActivity.this);
imageView.setLayoutParams(new AbsListView.LayoutParams(mWidth, mHeight));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
convertView = imageView;
}
ImageView imageView = (ImageView) convertView;
mBitmapUtils.display(imageView, getItem(position));
return convertView;
}
});
}
}
用于展示具体的某张图片
/** * 用于展示具体的某张图片 * Created by mChenys on 2016/1/24. */
public class PhotoViewActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
String photoPath = getIntent().getStringExtra("photo");
RelativeLayout rootView = new RelativeLayout(this);
//创建TextView显示照片的路径
TextView textView = new TextView(this);
RelativeLayout.LayoutParams tvLp = new RelativeLayout.LayoutParams(-1, -2);
tvLp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
textView.setLayoutParams(tvLp);
textView.setText(photoPath);
textView.setTextColor(Color.WHITE);
//创建支持缩放的ImageView
RelativeLayout.LayoutParams ivLp = new RelativeLayout.LayoutParams(-1, -1);
ZoomImageView zoomImageView = new ZoomImageView(this);
zoomImageView.setLayoutParams(ivLp);
zoomImageView.setImageBitmap(BitmapFactory.decodeFile(photoPath));
//添加ImageView
rootView.addView(zoomImageView);
//添加TextView
rootView.addView(textView);
setContentView(rootView);
}
}