Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發之圖片處理專題:利用AsyncTask和回調接口實現圖片的異步加載和壓縮

Android開發之圖片處理專題:利用AsyncTask和回調接口實現圖片的異步加載和壓縮

編輯:關於Android編程

在上一篇專題Android開發之圖片處理專題(一):利用軟引用構建圖片高速緩存中我們講述了如何利用軟引用技術構建高速緩存。那麼想要用到圖片,首先得有圖片的來源。一般而言,一個應用的圖片資源都是從服務器處獲得的。今天,我們利用Android開發之網絡請求通信專題(二):基於HttpClient的文件上傳下載裡面封裝好的httpUtils來實現圖片的下載,然後加載到本地配合軟引用緩存使用,以一個listView為例子來說明。

 

一、准備工作

我們需要准備以下幾個類(圖片對象和軟引用緩存類請參考上一篇專題):
1、圖片下載類ImageDownload 2、圖片下載工具FreedomHttpClientUtil(參考:Android開發之網絡請求通信專題(二):基於HttpClient的文件上傳下載) 3、圖片下載異步處理任務LoadTask 4、回調接口FreedomCallBack

二、工具類的編寫

1、回調接口的准備

public interface FreedomCallback {
	/**
	 * @Title: imageLoaded
	 * @Description: TODO
	 * @param imageDrawable 傳回的bitmap對象
	 * @param tag 用於listView查找控件
	 * @throws
	 */
	public void imageLoaded(Bitmap imageDrawable, Object tag);
}

2、圖片下載類和異步處理任務

圖片下載異步處理任務我們將其做成是圖片下載類的內部類來實現。
public class ImageDownload {
	private static final String TAG = "ImageDownload";
	private static String path;
	//構建緩存地址
	static {
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			File externalStorageDirectory = Environment
					.getExternalStorageDirectory();
			path = externalStorageDirectory.getAbsolutePath()
					+ ConstantValue.IMAGE_PATH;
			File directory = new File(path);
			if (!directory.exists()) {
				directory.mkdirs();
			}
		} else {
			path = null;
			Log.e(TAG, "no sdcard.");
		}
	}

	/**
	 * @Title: loadDrawable
	 * @Description: 下載圖片
	 * @param imageUrl
	 * @param simpleName
	 * @param imageCallback
	 * @throws
	 */
	public void loadDrawable(String imageUrl, String simpleName,
			FreedomCallback imageCallback) {
		new FreedomLoadTask(imageCallback).execute(imageUrl, simpleName);
	}

	/**
	 * @Title: loadImageFromUrl
	 * @Description: 根據地址下載圖片
	 * @param url
	 * @return
	 * @throws
	 */
	public Bitmap loadImageFromUrl(String url) {
		InputStream i = null;
		try {
			FreedomHttpClientUtil util = new FreedomHttpClientUtil();
			util.open(url, FreedomHttpClientUtil.GET);
			util.post();
			i = util.openInputStream();
			//拿到流後創建bitmap
			Bitmap bitmap = BitmapFactory.decodeStream(i);
			return bitmap;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * @Title: saveImage2SDCard
	 * @Description: 將圖片存放到SD卡中
	 * @param simpleName
	 * @param bitmap
	 * @throws
	 */
	public void saveImage2SDCard(String simpleName, Bitmap bitmap) {
		if (StringUtils.isNotBlank(path)) {
			File file = new File(new File(path), simpleName + ".png");

			FileOutputStream fOut = null;
			try {
				fOut = new FileOutputStream(file);
				//將bitmap寫入流中
				bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
				fOut.flush();
			} catch (Exception e) {
				org.cao.optimization.util.Log.info("文件無法創建");
				e.printStackTrace();
			} finally {
				if (fOut != null)
					try {
						fOut.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
			}

		}
	}

	/**
	 * @ClassName: FreedomLoadTask
	 * @author victor_freedom ([email protected])
	 * @createddate 2015-1-31 下午11:39:18
	 * @Description: 圖片下載,返回一個bitmap對象
	 */
	class FreedomLoadTask extends AsyncTask {
		private FreedomCallback imageCallback;

		public FreedomLoadTask(FreedomCallback imageCallback) {
			this.imageCallback = imageCallback;
		}

		@Override
		protected Bitmap doInBackground(String... params) {
			// 傳入兩個 參數,一個是下載路徑,一個是文件名稱
			Bitmap bitmap = loadImageFromUrl(params[0]);
			if (bitmap != null) {
				// 保存到SD卡中
				saveImage2SDCard(params[1], bitmap);
				// 加入緩存中
				ImageCache.getInstance().cacheImage(
						new Image(params[1], bitmap));
			}
			return bitmap;
		}

		@Override
		protected void onPostExecute(Bitmap result) {
			// 下載成功後執行回調接口
			imageCallback.imageLoaded(result, null);
			super.onPostExecute(result);
		}
	}

}

三、界面處理

1、Adapter處getView處理

我們假設adater只有一個ImageView,利用ViewHolder緩存,那麼在getView方法裡面,我們這樣處理:
	//拿到圖片的名字
		final String id = infos.getName();
		//給此處ImageView空間設置id
		continer.image.setTag(id);
		//根據名字首先從軟應用中拿到bitmap
		Image image = ImageCache.getInstance().getImage(id);
		Bitmap bitmap = image.getBitmap();
		//判斷bitmap是否為空
		if (bitmap == null) {

			// 判斷本地SDCard中是否有相關文件
			if (Image.hasFile(id)) {
				InputStream is;
				try {
					is = new FileInputStream(Image.getFileFromSDCard(id));
					bitmap = BitmapFactory.decodeStream(is);
					ImageCache.getInstance().cacheImage(new Image(id, bitmap));
					continer.image.setImageBitmap(bitmap);
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				}
			} else {
				//本地也沒有,就從服務器下載
				ImageDownload download = new ImageDownload();
				download.loadDrawable(news.getImgUrl(), id + "",
						new FreedomCallback() {

							@Override
							public void imageLoaded(Bitmap imageDrawable,
									Object tag) {
								if (imageDrawable != null) {
									//構建adapter時傳入的回調接口,如果下載圖片成功,回調此方法
									listCallback.imageLoaded(imageDrawable, id);
								}
							}
						});
				continer.image.setImageResource(R.drawable.ic_launcher);
			}

		} else {
			//如果軟引用還存在,則直接拿來用
			continer.image.setImageBitmap(bitmap);
		}

2、ListView初始化相關處理

 

	adapter = new NewsAdapter(context, new ListCallback() {

			@Override
			public void imageLoaded(Bitmap bitmap, Object tag) {
				//根據回調傳回的tag找到對應的ImageView
				ImageView imageView = (ImageView) listView.findViewWithTag(tag);
				if (imageView != null) {
					imageView.setImageBitmap(bitmap);
				}
			}
		});
		
		listView = new ListView(context);
		listView.setAdapter(adapter);

 

四、圖片壓縮

在上述過程中,我們還可以優化一下下。上述操作過程中,我們默認了下載下來的圖片的大小是已經設定好的。當然,在實際開發中,我們下載再來的圖片,可能也是和服務端溝通好設定好了。但是,有時候,圖片下載下來很大,這個時候,就需要對圖片進行壓縮了。一般而言,圖片的壓縮有兩種,質量壓縮和寬高壓縮。我們來看一個工具類。這是博主以前不知道從哪裡找來的了。
	//圖片質量壓縮
	public static Bitmap compressImage(Bitmap image) {

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 質量壓縮方法,這裡100表示不壓縮,把壓縮後的數據存放到baos中
		int options = 100;
		while (baos.toByteArray().length / 1024 > 100) { // 循環判斷如果壓縮後圖片是否大於100kb,大於繼續壓縮
			baos.reset();// 重置baos即清空baos
			image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 這裡壓縮options%,把壓縮後的數據存放到baos中
			options -= 10;// 每次都減少10
		}
		ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把壓縮後的數據baos存放到ByteArrayInputStream中
		Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream數據生成圖片
		return bitmap;
	}

	//圖片寬高壓縮
	public static Bitmap getimage(String srcPath) {
		BitmapFactory.Options newOpts = new BitmapFactory.Options();
		// 開始讀入圖片,此時把options.inJustDecodeBounds 設回true了
		newOpts.inJustDecodeBounds = true;
		Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);// 此時返回bm為空

		newOpts.inJustDecodeBounds = false;
		int w = newOpts.outWidth;
		int h = newOpts.outHeight;
		// 這個設置圖片的寬高,根據實際需要設定
		float hh = 800f;// 這裡設置高度為800f
		float ww = 480f;// 這裡設置寬度為480f
		// 縮放比。由於是固定比例縮放,只用高或者寬其中一個數據進行計算即可
		int be = 1;// be=1表示不縮放
		if (w > h && w > ww) {// 如果寬度大的話根據寬度固定大小縮放
			be = (int) (newOpts.outWidth / ww);
		} else if (w < h && h > hh) {// 如果高度高的話根據寬度固定大小縮放
			be = (int) (newOpts.outHeight / hh);
		}
		if (be <= 0)
			be = 1;
		newOpts.inSampleSize = be;// 設置縮放比例
		// 重新讀入圖片,注意此時已經把options.inJustDecodeBounds 設回false了
		bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
		return compressImage(bitmap);// 壓縮好比例大小後再進行質量壓縮
	}

有時候,我們還可以讓系統自動的給我們壓縮,只要確保不會出現OOM錯誤又能讓圖片以最大性能去展示

 

			File file = Image.getFileFromSDCard(name, "pure");
			Options opts = new Options();
			opts.inJustDecodeBounds = true;
			BitmapFactory.decodeFile(file.getAbsolutePath(), opts);
			opts.inJustDecodeBounds = false;
			// 根據設定的值讓系統自動壓縮,這行代碼的參數是第一個是BitmapFactory.Options,第二個參數是調整後圖片最小的寬或者高,第三個參數是調整後圖片的內存占用量上限。
			opts.inSampleSize = Util.computeSampleSize(opts, 600,(int) (1 * 1024 * 1024));
			opts.inDither = false;
			opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
			bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), opts);

 

圖片壓縮的步驟一般設定在圖片下載完之後。

至此,圖片從下載到顯示的所有流程,我們已經實現。當然,這只是一種實現方式,圖片的異步加載還可以有其他的實現方式。今天我們回顧了Android開發之網絡請求通信專題(二):基於HttpClient的文件上傳下載的內容裡封裝的httputils

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved