轉載聲明:Ryan的博客文章歡迎您的轉載,但在轉載的同時,請註明文章的來源出處,不勝感激! :-) java
http://my.oschina.net/ryanhoo/blog/93432 git
上節課咱們學習了緩存模塊的實現, 緩存分作兩份:Memory Cache和File Cache。方法也很簡單,分別是: github
區別在於內存緩存讀取優先,由於它讀寫的速度更快。可是考慮到內存限制,退而選用文件存儲,分擔內存緩存的壓力。 算法
原理很是簡單,在第一課中已經詳細分析了。那麼要怎麼才能將這個緩存模塊與UI模塊的顯示關聯起來呢?在這裏咱們須要一個控制器,掌管數據流向和讀寫,同時控制UI的顯示。 緩存
那麼這個控制器須要如下的元素: 服務器
//caches private MemoryCache memoryCache; private FileCache fileCache; //Asynchronous task private static AsyncImageLoader imageLoader;Memory Cache和File 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