之前项目有用到从相册选取多张图片的方法,之前项目紧基本都是在网上找了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会覆盖子类控件而直接获得焦点