效果图


这里主要用到了AsyncQueryHandler对象来查询手机图片资源,它内部是继承了Handler对象的.通过startQuery方法可以执行异步的查询.而如何使用ContentResolver的query方法的话,查询是在UI线程执行的,这样效果不太好,手机图片多的话,容易造成UI阻塞,通常如果采用这种方式的话,都会另起一个子线程来执行的,查询完毕在通过Handler发送消息来刷新UI,这种做法的话用起来感觉有点麻烦,因此采用AsyncQueryHandler将是一个不错的选择.

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 from5.            {@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 from10.        {@link #startInsert}.11. @param cookie the cookie object that's passed in from12.        {@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 from16.        {@link #startUpdate}.17. @param cookie the cookie object that's passed in from18.        {@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 from22.        {@link #startDelete}.23. @param cookie the cookie object that's passed in from24.        {@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);}@Overridepublic 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吧.文章最下边有下载地址.

MainActivity

用于展示相册列表

/*** 展示相册*/
public class MainActivity extends AppCompatActivity {private ListView mListView;private List<AlbumBean> mAlbumBeanList;@Overrideprotected 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()) {@Overrideprotected 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的whatObject cookie = null;//相当于message的objUri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;//查询的uriString[] 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() {@Overridepublic 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);}});}
}

PhotoListActivity

用于展示具体的某个相册

/**具体的某个相册* 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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);initData();initView();showPhotoList();initListener();}private void initListener() {mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic 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() {@Overridepublic int getCount() {return mPhotoList == null ? 0 : mPhotoList.size();}@Overridepublic String getItem(int position) {return mPhotoList == null ? "" : mPhotoList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic 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;}});}
}

PhotoViewActivity

用于展示具体的某张图片

/*** 用于展示具体的某张图片* Created by mChenys on 2016/1/24.*/
public class PhotoViewActivity extends Activity {@Overrideprotected 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);//创建支持缩放的ImageViewRelativeLayout.LayoutParams ivLp = new RelativeLayout.LayoutParams(-1, -1);ZoomImageView zoomImageView = new ZoomImageView(this);zoomImageView.setLayoutParams(ivLp);zoomImageView.setImageBitmap(BitmapFactory.decodeFile(photoPath));//添加ImageViewrootView.addView(zoomImageView);//添加TextViewrootView.addView(textView);setContentView(rootView);}
}

源码下载

自制Android手机相册相关推荐

  1. 基于android手机相册,基于安卓的手机图片分类软件的设计与实现.pdf

    ELECTRONICS WORLD ・技术交流 基于安卓的手机图片分类软件的设计与实现 武警工程大学研究生管理大队12队 张 鑫 武警广州指挥学院 姜 波 [摘要] 本文针对安卓手机中图片浏览器的快速 ...

  2. Android开发 调用系统相机相册图片功能,解决小米手机拍照或者图片横竖相反问题,及小米手机相册图片路径问题

    Android开发 调用系统相机相册图片功能,解决小米手机拍照或者图片横竖相反问题,及小米手机相册图片路径问题 1.调用相机,兼容7.0 AndroidManifest配置 <providera ...

  3. android调取手机相册或打开相机选择图片并显示

    作为一个android小白,自己想尝试写一个小项目,因此写个小博客记录一下自己的开发历程.这一篇记录自己学习调取手机相册以及打开相机选择图片并显示 示例是采用PopupWindow弹出底部菜单,选择相 ...

  4. 手机相册里android照片的来源,为什么手机相册总是出现不知道哪里来的照片?...

    安卓手机使用一段时候后,有时候手机相册会出现一些不知哪里来的照片,不清理的话还会慢慢增加.那么那些莫名其妙的照片到底来自哪里?删掉会有什么影响? 手机相册里莫名其妙的照片怎么来? 基于安卓手机开源的系 ...

  5. 三星 S4 手机误删除相片(相册)后的恢复问题,仅记录处理过程,其它Android手机同样适用...

    无意中删除了三星S4手机中相机的相册.过程是这样的,用手机拍了几张照片,觉得最后那张拍得不好,想删除,于是进入相册,看到有那张照片的图标,选择,删除,悲剧发生了! 这里得说三星的不好:在相册中,相册文 ...

  6. android打开手机相册获取真正的图片路径

    版权声明:本文为博主原创文章,转载请注明地址.    https://blog.csdn.net/huangxiaoguo1/article/details/79062341 根据打开相机返回的Uri ...

  7. android 地图相册,android开发实现view转bitmap保存到手机相册

    android开发实现view转bitmap保存到手机相册 直接贴代码,可以根据代码自行测试 //view转bitmap: public void SaveBitmapFromView(View vi ...

  8. android 相册相似图片,这样整理手机相册,容易引起极度舒适

    原标题:这样整理手机相册,容易引起极度舒适 手机拍照非常方便,大家平常都喜欢随手拍下各种照片去记录生活:此外,手机也常用来拍文件.笔记.PPT:还有屏幕截图.网络图片.表情包--日积月累整个相册凌乱不 ...

  9. Android获取手机相册图片

    1. 在AndroidManifest.XML中添加权限 <uses-permission android:name="android.permission.WRITE_EXTERNA ...

最新文章

  1. Kali Linux缺少ifconfig命令
  2. 陕西师范大学计算机科学学院公寓楼,陕西师范大学计算机科学学院简介
  3. [C++STL]list容器用法介绍
  4. 设计模式 -- 亨元模式(FlyWeight Pattern)
  5. mysql和oracle的mybatis操作
  6. linux安装软件imagemagick,Linux系统中怎么安装和使用ImageMagick软件?
  7. lombok系列(一)
  8. cuda cudnn 下载地址
  9. PEANUT西门子CNC OPC UA连接说明
  10. webservice接口开发学习笔记(一)
  11. 编译原理研究性学习专题 2——递归下降语法分析设计原理与实现
  12. lisp 设计盘形齿轮铣刀_用AutoLISP设计盘形齿轮铣刀渐开线齿形
  13. 景区门票预约系统_无预约,不出游!免费景区门票赶紧预约~
  14. win7 win 2008 R2多系统multi OS
  15. 基于Neo4j实现数据血缘管理
  16. 树莓派Pico开发板扩展ESP01S无线WiFi模块通信实践
  17. Leetcode——第108题
  18. 技术型公司与非技术型公司区别
  19. C#用IIS发布网站后localhost打不开127.0.0.1可以打开
  20. [PDF]我们经常使用的PDF是什么? PDF, PDF/A, PDF/Archive, OFD

热门文章

  1. C#使用wps转pdf
  2. Show me Why 软件破解教程目录 与 试看教程 更新工具和教程 (2015-04-22 更新试看链接)
  3. 保存的html打不开怎么办,win7系统收藏夹里储存的网页都打不开的解决方法
  4. gmoj 6087. 【GDOI2019模拟2019.3.26】获取名额 题解
  5. Python3实现基于ARIMA模型来预测茅台股票价格趋势
  6. H3C服务器出厂系统密码,h3c服务器网关口默认密码
  7. 单片机原理及应用——Arduino四驱四路循迹小车
  8. LF will be replaced by CRLF
  9. cfiledialog对话框大小_关于 CFileDialog 对话框多选功能的一个问题
  10. Mac系统 下载安装Android studio