之前项目有用到从相册选取多张图片的方法,之前项目紧基本都是在网上找了demo,然后直接复制到项目中,最近闲来无事,自己去摸索摸索,记录一下在写的过程中遇到的一些问题。

首先得从手机里面获取到所有的图片列表,就得提到两个ContentResolver和ContentProdider。ContentProdider我的理解为一个程序暴露自己的数据,ContentResolver为访问这个程序所暴露的数据,ContentResolver通过 getContentResolver()获取,通过query来查询需要获取的内容,返会的内容为Cursor。

下面是获取所有图片的代码片段:

Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
private HashMap<String, List<String>> hashMap = new HashMap<>();//储存图片的路径  以及图片的父文件的名字

while (cursor.moveToNext()) {
                    //获取图片路径
                    byte[] data = cursor.getBlob(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                    String imagePath = new String(data, 0, data.length - 1);//获取图片的路径
                    String parentPath = new File(imagePath).getParentFile().getName();//获取储存图片路径的父文件夹的名字
                    /**
                     * 在hashMap中分类储存同一个文件夹下面的图片
                     * */
                    if (hashMap.containsKey(parentPath)) {//如果hashMap中存在有这个文件夹就直接把图片信息放进去
                        hashMap.get(parentPath).add(imagePath);
                    } else {
                        List<String> imageList = new ArrayList<>();
                        imageList.add(imagePath);
                        hashMap.put(parentPath, imageList);
                    }
                }
                cursor.close();

下面说一下query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)这个查询方法,参数一Uri就是要查询内容的标识(如图片,联系人(ContactsContract.Contacts.CONTENT_URI)等) 。第二个参数projection相当于要查询的的条件,比如查询图片Id,名字什么的,例:new String[]{MediaStore.Images.Media._ID},传入null就是查询所有的信息。第三个参数相当于跟第二个参数再增加查询条件,例:MediaStore.Images.Media._ID+”= 1”,相当于查询了id为1的数据,传入null就是查询第二条件的所有。第四个参数也是配合第三个参数使用的,例:query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media._ID}
, MediaStore.Images.Media._ID+”=?”, new String[]{“1”}, null)传入null就是查询第三个参数所有。最后一个参数相当一排序,
例: MediaStore.Images.Media._ID+”DESC”,传入null就是默认的。HashMap为把图片按照文件夹的名字分类保存。(获取图片一般放在子线程中去获取,以免阻塞U主线程)

在展示图片的时候用的是GridView展示,在每个Item上面用了CheckBox来展示选中的状态,遇到一个问题,就是页面滑动时候,CheckBox会混乱。然后我用的方法解决是创建一个集合,保存CheckBox的选中状态来解决的,图片的加载展示用的是Glide,代码如下:
public abstract class GridViewAdapter extends BaseAdapter {
    private ArrayList<String> list;
    private Context context;
    private ArrayList<Boolean> isCheck;//保存选中状态,解决错乱问题
    private ArrayList<String> choiceImagePath = new ArrayList<>();//选中图片保存的集合


    public GridViewAdapter(Context context, ArrayList<String> list) {
        this.context = context;
        this.list = list;
        isCheck = new ArrayList<Boolean>();
        for (int i = 0; i < list.size(); i++) {
            isCheck.add(false);
        }
    }


    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int i) {
        return list.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(final int i, View view, ViewGroup viewGroup) {
        final ViewHolder viewHolder;
        String path = list.get(i);
        if (view == null) {
            viewHolder = new ViewHolder();
            view = LayoutInflater.from(context).inflate(R.layout.grid_group_item, null);
            viewHolder.mImageView = (ImageView) view.findViewById(R.id.mImageView);
            viewHolder.mCheckBox = (CheckBox) view.findViewById(R.id.mCheckBox);
            view.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) view.getTag();
        }
        viewHolder.mCheckBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (choiceImagePath.size() < 6) {
                    if (viewHolder.mCheckBox.isChecked()) {
                        isCheck.set(i, true);
                        choiceImagePath.add(list.get(i).toString());
                        ImagePath(choiceImagePath);
                    } else {
                        isCheck.set(i, false);
                        choiceImagePath.remove(list.get(i).toString());
                        ImagePath(choiceImagePath);
                    }
                } else {
                    Toast.makeText(context, "最多选取6长图片", Toast.LENGTH_SHORT).show();
                    isCheck.set(i, false);
                    viewHolder.mCheckBox.setChecked(false);
                }
            }
        });
        Glide.with(context).load(path).into(viewHolder.mImageView);
        if (viewHolder.mCheckBox.isChecked()) {
            viewHolder.mCheckBox.setChecked(true);
        } else {
            viewHolder.mCheckBox.setChecked(false);

        }
        viewHolder.mCheckBox.setChecked(isCheck.get(i));

        return view;
    }

    public class ViewHolder {
        private ImageView mImageView;
        private CheckBox mCheckBox;
    }

    protected abstract void ImagePath(ArrayList<String> choiceImagePath);

    ;
}

在记录一个问题,当item中存在有Button,CheckBox 等控件时候,这些控件会将焦点获取到,所以常常当点击item时候就没有响应,此时就要用到android:descendantFocusability=”blocksDescendants”,把这句话加载到Adapter中的布局里面,descendantFocusability有三个参数,分别代表的:
beforeDescendants:viewgroup会优先其子类控件而获取到焦点。
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点。
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点

简单的代码地址