android图片的打开和缩放时出现oom处理过程
- - CSDN博客移动开发推荐文章以前对于图片缩放时出现oom,也是束手无策. 昨天看了 Android_Tutor对于图片处理的文章,今天就斗胆将这部分的内容演习下. 首先创建一个布局文件:用imageview控件加载图片. 其次:用公共类ImageCacheUtil对图片进行压缩处理:这样可以保证图片太大的时候不会出现oom.
内容如题:
以前对于图片缩放时出现oom,也是束手无策。昨天看了 Android_Tutor对于图片处理的文章,今天就斗胆将这部分的内容演习下。
首先创建一个布局文件:用imageview控件加载图片
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/show" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello_world" /> <ImageView android:id="@+id/imageview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="matrix" android:src="@drawable/ic_launcher" /> </LinearLayout>
/** * @FILE:ImageCacheUtil.java * @AUTHOR:hui-ye * @DATE:2013-6-19 下午2:23:56 **/ package com.view.imagecachedemo; import java.io.InputStream; import android.content.ContentResolver; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.net.Uri; /******************************************* * * @CLASS:ImageCacheUtil * @DESCRIPTION:获得经过缩放处理的bitmap,以保证不会出现oom * @AUTHOR:hui-ye * @VERSION:v1.0 * @DATE:2013-6-19 下午2:23:56 *******************************************/ public class ImageCacheUtil { /** * @description:获取bitmap * @author:hui-ye * @param path 图片文件的路径 * @param data 图片的文件的数据 * @param context 上下文对象 * @param uri 资源 * @param target 模板宽或者高的大小 * @param width 是否是宽度 * @return: */ public static Bitmap getResizedBitmap(String path, byte[] data, Context context, Uri uri, int target, boolean width) throws Exception { // android api // BitmapFactory.Options options = new BitmapFactory.Options(); // options.inJustDecodeBounds = true; // BitmapFactory.decodeResource(getResources(), R.id.myimage, options); // int imageHeight = options.outHeight; // int imageWidth = options.outWidth; // String imageType = options.outMimeType; Bitmap bitmap = null; // 添加一个Options对象 Options options = null; if (target > 0) { options = new Options(); // 设置options的属性:inJustDecodeBounds=true的时候读取图片的时候,bitmap为null,将图片宽和高放到options中 options.inJustDecodeBounds = true; // 获得图片(这样会将图片的宽和高放入到options中) decode(path, data, context, uri, options); // 获得压缩的比例 int outWidth = options.outWidth; // 这样做宽和高就是相等了 if (!width) { outWidth = Math.max(outWidth, options.outHeight); } // 计算压缩比例 int ssize = sampleSize(outWidth, target); options.inSampleSize = ssize; // 设置inJustDecodeBounds = false,从新构建bitmap options.inJustDecodeBounds = false; bitmap = decode(path, data, context, uri, options); } return bitmap; } /** * @description:解析Bitmap的公用方法.注意各个方法的参数必须要有options * @author:hui-ye * @param path * @param data * @param context * @param uri * @param options * @return: */ public static Bitmap decode(String path, byte[] data, Context context, Uri uri, BitmapFactory.Options options) throws Exception { Bitmap bitmap = null; if (path != null) { bitmap = BitmapFactory.decodeFile(path, options); } else if (data != null) { BitmapFactory.decodeByteArray(data, 0, data.length, options); } else if (uri != null) { // uri不为空的时候context也不要为空.:ContentResolver;Uri内容解析器 ContentResolver resolver = context.getContentResolver(); InputStream is; is = resolver.openInputStream(uri); bitmap = BitmapFactory.decodeStream(is, null, options); } return bitmap; } /** * @description:获取samplesize图片的压缩比例 (这里就简单实现都是2的倍数啦.也就是說看width会是target的倍数) * @author:hui-ye * @param width * @param target * @return: */ private static int sampleSize(int width, int target) { int result = 1; for (int i = 0; i < 10; i++) { if (width < target * 2) { break; } width = width / 2; result = result * 2; } return result; } }
再次。打开相册,从中选择图片,进行压缩处理,将处理过的图片放到imageview中:
对于各个属性的说明:
/** * 打开本地相册的requestcode. */ public static final int OPEN_PHOTO_REQUESTCODE = 0x1; /** * 图片的target大小. */ private static final int target = 400; private ImageView image; /** * matrix:这是一个图片的变化矩阵(提供记录图片位置、记录图片缩放比例、实现图片移动等 ) */ private Matrix matrix; /** * curmatrix:记录图片当前位置的变换矩阵 */ private Matrix curmatrix; // 初始化模式参数 private int mode = 0; // 无模式 private static final int NONE = 0; // 拖拉模式 private static final int DRAG = 1; // 缩放模式 private static final int ZOOM = 2; /** * startPoint:第一个点的坐标 */ private PointF startPoint = new PointF();; /** * startDistance:缩放前两个点之间的距离 */ private float startDistance; /** * endDistance:缩放后两个点之间的距离 */ private float endDistance; /** * middlePoint:两个点之间的中点 */ private PointF middlePoint; /** * ZOOM_THRESHOLD:当两点的 startDistance距离大于ZOOM_THRESHOLD的时候才缩放 */ private static final float ZOOM_THRESHOLD = 10.0f; private Button show;
/** * @description:打开相册 * @author:hui-ye: */ private void setupViews() { Intent intent = new Intent(); intent.setAction(Intent.ACTION_PICK); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/jpeg"); startActivityForResult(intent, OPEN_PHOTO_REQUESTCODE); }
从相册中选择图片后,进行压缩处理,并将图片显示在imageview中
// 对startActivityForResult(intent,OPEN_PHOTO_REQUESTCODE );启动后的返回结果处理 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case OPEN_PHOTO_REQUESTCODE: if (resultCode == RESULT_OK) { Bitmap bitmap = null; // 将返回的数据构建成bitmap try { bitmap = ImageCacheUtil.getResizedBitmap(null, null, this, data.getData(), target, false); } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "生成图片失败", 1).show(); } if (bitmap != null) { // 为imageview设置图片 image.setImageBitmap(bitmap); } } break; default: break; } super.onActivityResult(requestCode, resultCode, data); }
// 这里对图片的缩放处理 image.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { // 取得第一个触控点的坐标 case MotionEvent.ACTION_DOWN: // 设置当前的模式为拖拉模式 mode = DRAG; // 记录图片当前的移动位置 curmatrix.set(image.getImageMatrix()); // 记录当前的坐标 startPoint.set(event.getX(), event.getY()); break; // 屏幕上已经有触控点了 case MotionEvent.ACTION_POINTER_DOWN: // 如果是两点触控,则将mode设置为缩放模式 mode = ZOOM; // 获取当前坐标和第一个坐标之间的距离 startDistance = spacing(event); if (startDistance > ZOOM_THRESHOLD) { // 获取两点之间的中点 middlePoint = getMiddlePoint(event); // 记录图片当前的缩放比例 curmatrix.set(image.getImageMatrix()); } break; // 判断触控点的移动(一个点移动还是多点移动 ) case MotionEvent.ACTION_MOVE: // 一个点的移动为拖拉模式 if (mode == DRAG) { // 获取x轴的移动距离 float distanceX = event.getX() - startPoint.x; // 获取y轴的移动距离 float distanceY = event.getY() - startPoint.y; // 设置 移动变换 curmatrix.set(image.getImageMatrix()); // 设置图片的移动 matrix.postTranslate(distanceX, distanceY); } else if (mode == ZOOM) { // 结束距离 endDistance = spacing(event); if (endDistance > ZOOM_THRESHOLD) { // 缩放比例 float scale = endDistance / startDistance; matrix.set(curmatrix); matrix.postScale(scale, scale, middlePoint.x, middlePoint.y); } } case MotionEvent.ACTION_UP: // 当手指离开屏幕,但屏幕上仍有其他触点(手指)时触发该事件 case MotionEvent.ACTION_POINTER_UP: mode = NONE; break; default: break; } image.setImageMatrix(matrix); return true; } });
// 计算移动距离 private float spacing(MotionEvent event) { // event.getX(0)第一个点坐标,event.getX(1)为第二个点的坐标 float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return FloatMath.sqrt(x * x + y * y); } /** * @description:获得两个点的中点坐标 * @author:hui-ye * @param event * @return: */ public static PointF getMiddlePoint(MotionEvent event) { float x = (event.getX(0) + event.getX(1)) / 2; float y = (event.getY(0) + event.getY(1)) / 2; return new PointF(x, y); }
附件是完整的程序代码