天天看點

Android ImageLoader(Android-Universal-Image-Loader)【1】概述及使用簡介



Android ImageLoader(Android-Universal-Image-Loader)【1】概述及使用簡介

一,前言:為什麼要引入Android-Universal-Image-Loader?

衆所周知,簡單的幾個ImageView加載幾個圖像資源、或者這幾個圖像資源是從本地加載時無需考慮過多直接加載即可,但當成千上百個ImageView加載成千上百個圖像、尤其是當這些圖檔還是從網絡中異步擷取,那麼需要考慮的問題細節很多很繁瑣且容易出錯,現在随便舉例其中幾條:

(1)最基本的問題,網絡不可靠,可能在不可靠網絡加載過程中,圖檔加載發生難以預估的失敗。

(2)已經從網絡或本地中加載成功的圖檔,應該避免重複加載,重複加載造成網絡流量浪費,以及裝置計算資源的重複浪費,是以需要考慮圖檔緩存政策。緩存分為兩級緩存:第一級:記憶體緩存,第二級:“硬碟”緩存(通常是手機的外置存儲如SD卡和内置存儲)。實作這樣的層級緩存政策需要自己維護群組織。記憶體緩存可以考慮使用Android的LruCache,詳情參考我的另外兩篇文章:

a、《使用新式LruCache取代SoftReference緩存圖檔,Android異步加載圖檔》,文章連結位址:

http://blog.csdn.net/zhangphil/article/details/43667415 b、或者自己按照LruCache設計思路實作和管理記憶體管理,《基于Java LinkedList,實作Android大資料緩存政策》,文章連結位址: http://blog.csdn.net/zhangphil/article/details/44116885

硬碟緩存則要自己建立緩存索引和緩存檔案結構(如何建立緩存目錄?記憶體在何時機把硬碟緩存的圖檔加入等等問題)。

(3)設想這一種情況,在一個Android豎直方向上ListView中有成千上萬條圖檔item,每條item中的圖檔均需從網絡擷取。使用者手指在螢幕上快速滑動,滑動過程中,極有可能可見視野内的圖檔還沒有加載完成後,使用者已經快速的往下滑看下面的圖檔去了。而上面已經消失的圖檔加載線程如果置之不理任由其運作,那麼,當使用者在不斷的下拉和上拉過程中,将會造成線程不斷的重建和運作,記憶體開銷極大。而對于使用者來來,最緊迫的目前可見視野的圖檔加載顯示可能因為線程過多而被無限期拖延到最後顯示。這種情況一般得應對政策師自己維護和管理一個線程池(關于Java線程池,詳情請參考我的另外一篇文章:《Java線程池:ExecutorService,Executors》,文章連結位址:

http://blog.csdn.net/zhangphil/article/details/43898637

),自己管理和維護多線程下載下傳任務隊列,顯然,需要考慮的線程隊列問題很多,很繁瑣。

等等還有很多未列舉出來的細節問題。

為了避免重複造輪子,這種情況下最好考慮使用一些業界比較成熟穩定的開源架構。

Android ImageLoader(Android-Universal-Image-Loader),是github上的一個第三方開源圖像加載庫。該項目在github上的連結位址:

https://github.com/nostra13/Android-Universal-Image-Loader

Android-Universal-Image-Loader主要應用領域是ImageView加載圖檔。該開源架構對上述問題給予了充分的解決。并提供了其他額外的附加功能(如加載的圖檔尺寸,加載動畫等等)。

二、Android-Universal-Image-Loader使用簡介。

首先到Android-Universal-Image-Loader官方網址下載下傳項目包,使用可以分為兩種方法

(1)把Android-Universal-Image-Loader的全部實作源代碼(*.java)放入到自己的項目目錄src下,當作是自己的源代碼使用。

(2)導入Android-Universal-Image-Loader的jar庫檔案,比如universal-image-loader-1.9.4.jar。

兩種方式都可以,看個人偏好。

我用的是第一種方法,這樣可以友善查閱甚至直接二次定制修改Android-Universal-Image-Loader的源代碼為自己所用。

代碼結構層次如圖:

然後就可以直接使用,現給出一個示例。

測試用的MainActivity.java:

package zhangphil.imageloader;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;

public class MainActivity extends ListActivity {

	private ImageLoader mImageLoader = null;

	// 加載的圖檔資源URL
	private final String ZHANGPHIL_CSDN_LOGO_URL = "http://avatar.csdn.net/9/7/A/1_zhangphil.jpg";

	// 加載的數目,假定資料總量很大
	private final int ITEM_COUNT = 10000;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		ListView lv = this.getListView();
		ArrayAdapter adapter = new MyArrayAdapter(this, -1);
		lv.setAdapter(adapter);

		mImageLoader = ImageLoader.getInstance();
		mImageLoader.init(getImageLoaderConfiguration());
	}

	private ImageLoaderConfiguration getImageLoaderConfiguration() {

		ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
				this)
				.threadPoolSize(3)
				// 線程數量
				.threadPriority(Thread.NORM_PRIORITY)
				// 線程優先級
				.tasksProcessingOrder(QueueProcessingType.FIFO)
				.denyCacheImageMultipleSizesInMemory()
				.memoryCacheSize(1024 * 1024 * 10) // 記憶體緩存的容量10MB
				.diskCacheFileCount(100)// 緩存的檔案數量
				.diskCacheSize(1024 * 1014 * 100)// 硬碟緩存的大小100MB
				.writeDebugLogs()// 輸出日志
				.build();

		return config;
	}

	private DisplayImageOptions getDisplayImageOptions() {

		DisplayImageOptions options = new DisplayImageOptions.Builder()
				.showImageOnLoading(R.drawable.loading)
				// 加載過程中顯示的圖檔
				.showImageForEmptyUri(R.drawable.ic_launcher)
				// 空URI顯示的圖檔
				.showImageOnFail(R.drawable.error)
				// 加載失敗時候顯示内容
				.cacheInMemory(true)
				// 緩存到記憶體
				.cacheOnDisk(true)
				// 緩存到硬碟
				.considerExifParams(true)
				.displayer(new FadeInBitmapDisplayer(1000))// 淡入加載圖檔顯示
				.build();

		return options;
	}

	private class MyArrayAdapter extends ArrayAdapter {

		private LayoutInflater inflater;
		private int resId = R.layout.item;
		private DisplayImageOptions mDisplayImageOptions;

		public MyArrayAdapter(Context context, int resource) {
			super(context, resource);
			inflater = LayoutInflater.from(getContext());
			mDisplayImageOptions = getDisplayImageOptions();
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			if (convertView == null)
				convertView = inflater.inflate(resId, null);

			ImageView imageView = (ImageView) convertView
					.findViewById(R.id.image);
			mImageLoader.displayImage(ZHANGPHIL_CSDN_LOGO_URL, imageView,
					mDisplayImageOptions);

			return convertView;
		}

		@Override
		public int getCount() {
			return ITEM_COUNT;
		}
	}
	
	
	// private File getMyCacheDir() {
	// File sdRoot = Environment.getExternalStorageDirectory();
	// String myImageLoaderCacheFileDir = "ImageLodaerCache";
	// File cacheFileDir = new File(sdRoot, myImageLoaderCacheFileDir);
	// return cacheFileDir;
	// }
}
           

Item.xml檔案:

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/image" >
    
</ImageView>
           

素材error.png和Loading.gif可以根據個人的需要選取不同的圖檔資源。

ImageLoader在使用之前需要做一些初始化工作,配置ImageLoaderConfiguration和DisplayImageOptions 。然後就可以直接使用ImageLoader的displayImage()方法從網絡或本地存儲中異步加載圖檔資源。而關于圖檔資源的緩存和異步下載下傳線程池隊列則交由ImageLoader為我們妥善在背景管理好。