Android简单的图片浏览器demo遇到的各种坑
最近在做一个用户反馈的模块,可以上传最多三张图片,点击小图片后跳转到图片浏览器,可以查看图片。
图像处理是个很消耗内存的事情,android中对Bitmap的处理需要格外小心,一个不留神你的应用可能就因为Bitmap导致oom。
首先点击加号按钮可以打开系统图片浏览器,选择图片,并返回图片的Uri,在加号按钮的点击事件中发送Intent:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
intent.putExtra("return-data",true);
Rc.m_pActivity.startActivityForResult(intent, GET_LOCAL_IMAGE_REQUEST_CODE);
Rc.m_pActivity
是项目全局存储的Activity的实例,如果是在Activity中实现,替换成对应的Activity实例即可。
在系统图片浏览器中选择相应的图片后返回到自己的Activity,然后返回图片的Uri,我们对Uri做相应的处理,并使其显示在界面上。
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
// Bitmap cameraBitmap = (Bitmap) data.getExtras().get("data");
// mAddScreenImage1.setImageBitmap(cameraBitmap);
switch (requestCode) {
case GET_LOCAL_IMAGE_REQUEST_CODE:
ContentResolver resolver = Rc.m_pActivity.getContentResolver();
//照片的原始资源地址
Uri originalUri = data.getData();
try {
//使用ContentProvider通过URI获取原始图片
Bitmap photo = MediaStore.Images.Media.getBitmap(resolver, originalUri);
if (photo != null) {
//为防止原始图片过大导致内存溢出,这里先缩小原图显示,然后释放原始Bitmap占用的内存
Bitmap smallBitmap = GalleryActivity.zoomImage(photo, Rc.GetIns().Dip2Pix(48), Rc.GetIns().Dip2Pix(48));
//释放原始图片占用的内存,防止out of memory异常发生
photo.recycle();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
}
zoomImage(Bitmap bitmap, double width, double height)
是个封装的方法,是为了缩小成缩略图,同时防止图片过大导致oom。方法如下:
public static Bitmap zoomImage(Bitmap bmp, double newWidth,
double newHeight) {
// 获取这个图片的宽和高
float width = bmp.getWidth();
float height = bmp.getHeight();
// 创建操作图片用的matrix对象
Matrix matrix = new Matrix();
// 计算宽高缩放率
float scaledWidth = ((float) newWidth) / width;
float scaledHeight = ((float) newHeight) / height;
// 缩放图片动作
matrix.postScale(scaledWidth, scaledHeight);
Bitmap bitmap = Bitmap.createBitmap(bmp, 0, 0, (int) width,
(int) height, matrix, true);
return bitmap;
}
接下来要做的就是将用户选择的图片的Uri装到一个ArrayList中,然后通过Intent传递给自己写的图片浏览器的Activity。
本来GalleryActivity(图片浏览器)是想用TabHost+ViewPager来实现的,但是好像TabHost的每一个Tab都得是一个Activity和Fragment不知道好不好添加View,另外可能是想尝试一下RecyclerView,就采用了ViewPager(上面的大图浏览区域)+RecyclerView(下面的下图预览区域)的实现方式,如果有TabHost的独特优势或者更加好的方式,欢迎指教。
在GalleryActivity中ViewPager的每一个页是一个ImageView,每个RecyclerView的item也是一个ImageView,具体实现不详述了。这里主要说的是图片处理中的问题,开始的时候直接将图片添加到ImageView中,遇到稍微大一点的图片,ViewPager就无法显示,后来对图片进行了自适应屏幕和缩放的处理,才解决了这个问题,缩放的方法就是上面的方法。下面贴上自适应屏幕的处理方法。
private Bitmap createScaledBitmap(Bitmap bitmap){
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels+1;
int height = dm.heightPixels+1;
int t_width;
int t_height;
if (bitmap.getWidth()>width || bitmap.getHeight()>height){
t_width = width;
t_height = bitmap.getHeight()*width/bitmap.getWidth();
if (t_height>height){
t_width = t_width*height/t_height;
t_height = height;
}
} else
if (bitmap.getWidth()<width && bitmap.getHeight()<height){
t_width = width;
t_height = bitmap.getHeight()*width/bitmap.getWidth();
if (t_height>height){
t_width = t_width*height/t_height;
t_height = height;
}
} else {
t_width = bitmap.getWidth();
t_height = bitmap.getHeight();
}
return Bitmap.createScaledBitmap(bitmap, t_width, t_height, true);
}
下面的RecyclerView的item小图还需要圆角处理,所以又从网上找了个圆角处理的方法:
private Bitmap getRoundedCornerBitmap(Bitmap bitmap, float radius) {
try {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(),
bitmap.getHeight());
final RectF rectF = new RectF(new Rect(0, 0, bitmap.getWidth(),
bitmap.getHeight()));
final float roundPx = radius;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.BLACK);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
final Rect src = new Rect(0, 0, bitmap.getWidth(),
bitmap.getHeight());
canvas.drawBitmap(bitmap, src, rect, paint);
return output;
} catch (Exception e) {
return bitmap;
}
}
还有一个比较坑的地方,是在使用RecyclerView的时候,设置方向是水平,宽度为wrap_content,然后使其居中,开始在android studio上面的时候这个效果是好的,但是后来我原封不动的拷贝到我们eclipse结构的项目中时,结果竟然不好用了!!!后来把android studio中的包拷贝过来,又出现了其他一些类找不到的问题,难道是我拷错了包?算了,项目里的包也不太好换,怕出问题背锅,所以只能通过设置ItemDecoration来解决了。
class SpaceItemDecoration extends RecyclerView.ItemDecoration{
private int space;
public SpaceItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
int itemCount = images.size();
int pos = parent.getChildAdapterPosition(view);
//设定item之间的间隔
if (pos != (itemCount -1)) {
outRect.right = space;
} else {
outRect.right = 0;
}
//动态设定四周的边距
outRect.top = Rc.GetIns().Dip2Pix(100) - mUsedBitmaps.get(pos).getHeight();
WindowManager wm = GalleryActivity.this.getWindowManager();
Rect screenSize = new Rect();
wm.getDefaultDisplay().getRectSize(screenSize);
int width = screenSize.width();
if (pos == 0) {
outRect.left = (width - Rc.GetIns().Dip2Pix((mUsedBitmaps.size() - 1)
* (SMALL_PREVIEW_IMAGE_WIDTH + PREVIEW_IMAGE_SPACE) + BIG_PREVIEW_IMAGE_WIDTH)) / 2;
}
}
}
动态的设定边距,然后previewGallery.addItemDecoration(new SpaceItemDecoration(
使其生效。
Rc.GetIns().Dip2Pix(PREVIEW_IMAGE_SPACE)))
好了,要记录的大概就这些,如果各位有指教,欢迎留言!