【構建Android緩存模塊】(三)Controller & 異步圖片加載

聲明:Ryan的博客文章歡迎您的轉載,但在轉載的同時,請註明文章的來源出處,不勝感激! :-)  java

http://my.oschina.net/ryanhoo/blog/93432 git

    節課咱們學習了緩存模塊的實現, 緩存分作兩份:Memory CacheFile Cache。方法也很簡單,分別是: github

  • 存儲文件
  • 按惟一key值索引文件
  • 清空緩存

    區別在於內存緩存讀取優先,由於它讀寫的速度更快。可是考慮到內存限制,退而選用文件存儲,分擔內存緩存的壓力。 算法

    原理很是簡單,在第一課中已經詳細分析了。那麼要怎麼才能將這個緩存模塊與UI模塊的顯示關聯起來呢?在這裏咱們須要一個控制器,掌管數據流向和讀寫,同時控制UI的顯示。 緩存

    那麼這個控制器須要如下的元素: 服務器

  • 內存緩存
  • 硬盤緩存
  • 異步任務處理
  • 控制UI顯示
//caches
private MemoryCache memoryCache;
private FileCache fileCache;
//Asynchronous task
private static AsyncImageLoader imageLoader;
    Memory CacheFile Cache在上一課中有具體的實現,這裏有一個異步的任務處理器—— AsyncImageDownloader,它用來在後臺下載數據,完成下載後存儲數據到緩存中,並更新UI的顯示 。讓咱們來看看它是如何實現的:
class AsyncImageDownloader extends AsyncTask<Void, Void, Bitmap>{
	private ImageView imageView;
	private String fileName;
	
	public AsyncImageDownloader(ImageView imageView, String fileName){
		this.imageView = imageView;
		this.fileName = fileName;
	}
	
	@Override
	protected void onPreExecute() {
		super.onPreExecute();
		imageView.setImageResource(R.drawable.placeholder);
	}
	
	@Override
	protected Bitmap doInBackground(Void... arg0) {
		String url = Utils.getRealUrlOfPicture(fileName);
		HttpResponse response = new HttpRetriever().requestGet(url, null);
		Log.i(TAG, "url: " + url);
		Log.i(TAG, "respone: " + response);
		InputStream in = null;
		try {
			if(response != null && response.getEntity() != null)
				in = response.getEntity().getContent();
		} catch (IllegalStateException e) {
			e.printStackTrace();
			return null;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		
		//TODO to be optimized: adjust the size of bitmap
		return BitmapFactory.decodeStream(in);
	}
	
	@Override
	protected void onPostExecute(Bitmap result) {
		super.onPostExecute(result);
		if(result != null && imageView != null)
			imageView.setImageBitmap(result);
		
		//TODO cache the bitmap both in sdcard & memory
		memoryCache.put(fileName, result);// key is a unique token, value is the bitmap
		
		fileCache.put(fileName, result);
	}
}

    能夠看到這個類的構造函數須要兩個參數,分別是文件名和對應要顯示的ImageView,那麼在任務開始的時候,能夠爲該ImageView設置未下載狀態的圖片,而後下載完成後更新UI。 框架

    須要提醒的是,這裏的惟一key值,我使用的是文件名,由於我接收到的文件名是惟一的。猿媛們也能夠根據本身的需求,設計本身的惟一key值算法。 異步

    接下來,咱們須要讀用key值索引相應的Bitmap: ide

public Bitmap getBitmap(String key){
	Bitmap bitmap = null;
	//1. search memory
	bitmap = memoryCache.get(key);
	
	//2. search sdcard
	if(bitmap == null){
		File file = fileCache.getFile(key);
		if(file != null)
			bitmap = BitmapHelper.decodeFile(file, null);
	}
	
	return bitmap;
}

    讀取到Bitmap後進行顯示: 函數

public void displayBitmap(ImageView imageView, String fileName){
	//no pic for this item
	if(fileName == null || "".equals(fileName))
		return;
	
	Bitmap bitmap = getBitmap(fileName);
	//search in cache, if there is no such bitmap, launch downloads
	if(bitmap != null){
		imageView.setImageBitmap(bitmap);
	}
	else{
		Log.w(TAG, "Can't find the file you required.");
		new AsyncImageDownloader(imageView, fileName).execute();
	}
}
    到這裏,一個簡單的緩存框架就搭建成功了。它簡潔有效,可是很是單薄,彷佛不夠強大,須要大家根據本身的需求進行修改。另外它原本的目的就是用於演示,理解這個之後,咱們再來看Google的BitmapFun。

    不過,我將它應用在一個小項目中,性能還不錯。對於小項目的需求,應該是夠的。

    最後,附上使用方法,以及整個類的源碼。

    使用方法:

AsyncImageLoader imageLoader = AsyncImageLoader.getInstance(this);、
imageLoader.displayBitmap(imageView, fileName);

    源碼:

public class AsyncImageLoader { private static final String TAG = "AsyncImageLoader"; //caches private MemoryCache memoryCache; private FileCache fileCache; //Asynchronous task private static AsyncImageLoader imageLoader; class AsyncImageDownloader extends AsyncTask<Void, Void, Bitmap>{ private ImageView imageView; private String fileName; public AsyncImageDownloader(ImageView imageView, String fileName){ this.imageView = imageView; this.fileName = fileName; } @Override protected void onPreExecute() { super.onPreExecute(); imageView.setImageResource(R.drawable.placeholder); } @Override protected Bitmap doInBackground(Void... arg0) { String url = Utils.getRealUrlOfPicture(fileName); HttpResponse response = new HttpRetriever().requestGet(url, null); Log.i(TAG, "url: " + url); Log.i(TAG, "respone: " + response); InputStream in = null; try { if(response != null && response.getEntity() != null) in = response.getEntity().getContent(); } catch (IllegalStateException e) { e.printStackTrace(); return null; } catch (IOException e) { e.printStackTrace(); return null; } //TODO to be optimized: adjust the size of bitmap return BitmapFactory.decodeStream(in); } @Override protected void onPostExecute(Bitmap result) { super.onPostExecute(result); if(result != null && imageView != null) imageView.setImageBitmap(result); //TODO cache the bitmap both in sdcard & memory memoryCache.put(fileName, result);// key is a unique token, value is the bitmap fileCache.put(fileName, result); } } private AsyncImageLoader(Context context){ this.memoryCache = new MemoryCache(); this.fileCache = new FileCache(context); } public static AsyncImageLoader getInstance(Context context){ if(imageLoader == null) imageLoader = new AsyncImageLoader(context); return imageLoader; } public void displayBitmap(ImageView imageView, String fileName){ //no pic for this item if(fileName == null || "".equals(fileName)) return; Bitmap bitmap = getBitmap(fileName); //search in cache, if there is no such bitmap, launch downloads if(bitmap != null){ imageView.setImageBitmap(bitmap); } else{ Log.w(TAG, "Can't find the file you required."); new AsyncImageDownloader(imageView, fileName).execute(); } } public Bitmap getBitmap(String key){ Bitmap bitmap = null; //1. search memory bitmap = memoryCache.get(key); //2. search sdcard if(bitmap == null){ File file = fileCache.getFile(key); if(file != null) bitmap = BitmapHelper.decodeFile(file, null); } return bitmap; } public void clearCache(){ if(memoryCache != null) memoryCache.clear(); if(fileCache != null) fileCache.clear(); } }


源碼:

附上源碼,不過服務器的源碼暫時尚未放出來,先看看客戶端的吧。

https://github.com/ryanhoo/SoftRead

相關文章
相關標籤/搜索