自制Android手机相册

效果图

这里写图片描述


这里主要用到了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 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吧.文章最下边有下载地址.

MainActivity

用于展示相册列表

/**
 * 展示相册
 */
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);
            }
        });
    }
}

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;

    @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;
            }
        });
    }
}

PhotoViewActivity

用于展示具体的某张图片

/**
 * 用于展示具体的某张图片
 * 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);
    }
}

源码下载

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值