现在的位置: 首页 > 综合 > 正文

android图片的打开和缩放时出现oom处理过程

2014年02月20日 ⁄ 综合 ⁄ 共 6734字 ⁄ 字号 评论关闭

内容如题:

以前对于图片缩放时出现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>

其次:用公共类ImageCacheUtil对图片进行压缩处理:这样可以保证图片太大的时候不会出现oom

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

好了,介绍就到此为止,其他的希望大家去研究 android API   http://developer.android.com/training/displaying-bitmaps/index.html

附件是完整的程序代码

抱歉!评论已关闭.