android圖片的打開和縮放時出現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>

其次:用公共類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

附件是完整的程序代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章