【構建Android快取模組】(三)Controller & 非同步圖片載入
上節課我們學習了快取模組的實現, 快取分做兩份:Memory Cache和File Cache。方法也很簡單,分別是:
- 儲存檔案
- 按唯一key值索引檔案
- 清空快取
區別在於記憶體快取讀取優先,因為它讀寫的速度更快。但是考慮到記憶體限制,退而選用檔案儲存,分擔記憶體快取的壓力。
原理非常簡單,在第一課中已經詳細分析了。那麼要怎麼才能將這個快取模組與UI模組的顯示關聯起來呢?在這裡我們需要一個控制器,掌管資料流向和讀寫,同時控制UI的顯示。
那麼這個控制器需要以下的元素:
- 記憶體快取
- 硬碟快取
- 非同步任務處理
- 控制UI顯示
1 |
//caches |
2 |
private MemoryCache
memoryCache; |
3 |
private FileCache
fileCache; |
4 |
//Asynchronous
task |
5 |
private static AsyncImageLoader
imageLoader; |
01 |
class AsyncImageDownloader extends AsyncTask<Void,
Void, Bitmap>{ |
02 |
private ImageView
imageView; |
03 |
private String
fileName; |
04 |
|
05 |
public AsyncImageDownloader(ImageView
imageView, String fileName){ |
06 |
this .imageView
= imageView; |
07 |
this .fileName
= fileName; |
08 |
} |
09 |
|
10 |
@Override |
11 |
protected void onPreExecute()
{ |
12 |
super .onPreExecute(); |
13 |
imageView.setImageResource(R.drawable.placeholder); |
14 |
} |
15 |
|
16 |
@Override |
17 |
protected Bitmap
doInBackground(Void... arg0) { |
18 |
String
url = Utils.getRealUrlOfPicture(fileName); |
19 |
HttpResponse
response = new HttpRetriever().requestGet(url, null ); |
20 |
Log.i(TAG, "url:
" +
url); |
21 |
Log.i(TAG, "respone:
" +
response); |
22 |
InputStream
in = null ; |
23 |
try { |
24 |
if (response
!= null &&
response.getEntity() != null ) |
25 |
in
= response.getEntity().getContent(); |
26 |
} catch (IllegalStateException
e) { |
27 |
e.printStackTrace(); |
28 |
return null ; |
29 |
} catch (IOException
e) { |
30 |
e.printStackTrace(); |
31 |
return null ; |
32 |
} |
33 |
|
34 |
//TODO
to be optimized: adjust the size of bitmap |
35 |
return BitmapFactory.decodeStream(in); |
36 |
} |
37 |
|
38 |
@Override |
39 |
protected void onPostExecute(Bitmap
result) { |
40 |
super .onPostExecute(result); |
41 |
if (result
!= null &&
imageView != null ) |
42 |
imageView.setImageBitmap(result); |
43 |
|
44 |
//TODO
cache the bitmap both in sdcard & memory |
45 |
memoryCache.put(fileName,
result); //
key is a unique token, value is the bitmap |
46 |
|
47 |
fileCache.put(fileName,
result); |
48 |
} |
49 |
} |
可以看到這個類的建構函式需要兩個引數,分別是檔名和對應要顯示的ImageView,那麼在任務開始的時候,可以為該ImageView設定未下載狀態的圖片,然後下載完成後更新UI。
注:需要提醒的是,這裡的唯一key值,我使用的是檔名,因為我接收到的檔名是唯一的。猿媛們也可以根據自己的需求,設計自己的唯一key值演算法。
接下來,我們需要讀用key值索引相應的Bitmap:
01 |
public Bitmap
getBitmap(String key){ |
02 |
Bitmap
bitmap = null ; |
03 |
//1.
search memory |
04 |
bitmap
= memoryCache.get(key); |
05 |
|
06 |
//2.
search sdcard |
07 |
if (bitmap
== null ){ |
08 |
File
file = fileCache.getFile(key); |
09 |
if (file
!= null ) |
10 |
bitmap
= BitmapHelper.decodeFile(file, null ); |
11 |
} |
12 |
|
13 |
return bitmap; |
14 |
} |
讀取到Bitmap後進行顯示:
01 |
public void displayBitmap(ImageView
imageView, String fileName){ |
02 |
//no
pic for this item |
03 |
if (fileName
== null || "" .equals(fileName)) |
04 |
return ; |
05 |
|
06 |
Bitmap
bitmap = getBitmap(fileName); |
07 |
//search
in cache, if there is no such bitmap, launch downloads |
08 |
if (bitmap
!= null ){ |
09 |
imageView.setImageBitmap(bitmap); |
10 |
} |
11 |
else { |
12 |
Log.w(TAG, "Can't
find the file you required." ); |
13 |
new AsyncImageDownloader(imageView,
fileName).execute(); |
14 |
} |
15 |
} |
不過,我將它應用在一個小專案中,效能還不錯。對於小專案的需求,應該是夠的。
最後,附上使用方法,以及整個類的原始碼。
使用方法:
1 |
AsyncImageLoader
imageLoader = AsyncImageLoader.getInstance( this );、 |
2 |
imageLoader.displayBitmap(imageView,
fileName); |
原始碼:
001 |
<strong> public class AsyncImageLoader
{ |
002 |
003 |
private static final String
TAG = "AsyncImageLoader" ; |
004 |
|
005 |
//caches |
006 |
private MemoryCache
memoryCache; |
007 |
private FileCache
fileCache; |
008 |
//Asynchronous
task |
009 |
private static AsyncImageLoader
imageLoader; |
010 |
011 |
class AsyncImageDownloader extends AsyncTask<Void,
Void, Bitmap>{ |
012 |
private ImageView
imageView; |
013 |
private String
fileName; |
014 |
|
015 |
public AsyncImageDownloader(ImageView
imageView, String fileName){ |
016 |
this .imageView
= imageView; |
017 |
this .fileName
= fileName; |
018 |
} |
019 |
|
020 |
@Override |
021 |
protected void onPreExecute()
{ |
022 |
super .onPreExecute(); |
023 |
imageView.setImageResource(R.drawable.placeholder); |
024 |
} |
025 |
|
026 |
@Override |
027 |
protected Bitmap
doInBackground(Void... arg0) { |
028 |
String
url = Utils.getRealUrlOfPicture(fileName); |
029 |
HttpResponse
response = new HttpRetriever().requestGet(url, null ); |
030 |
Log.i(TAG, "url:
" +
url); |
031 |
Log.i(TAG, "respone:
" +
response); |
032 |
InputStream
in = null ; |
033 |
try { |
034 |
if (response
!= null &&
response.getEntity() != null ) |
035 |
in
= response.getEntity().getContent(); |
036 |
} catch (IllegalStateException
e) { |
037 |
e.printStackTrace(); |
038 |
return null ; |
039 |
} catch (IOException
e) { |
040 |
e.printStackTrace(); |
041 |
return null ; |
042 |
} |
043 |
|
044 |
//TODO
to be optimized: adjust the size of bitmap |
045 |
return BitmapFactory.decodeStream(in); |
046 |
} |
047 |
|
048 |
@Override |
049 |
protected void onPostExecute(Bitmap
result) { |
050 |
super .onPostExecute(result); |
051 |
if (result
!= null &&
imageView != null ) |
052 |
imageView.setImageBitmap(result); |
053 |
|
054 |
//TODO
cache the bitmap both in sdcard & memory |
055 |
memoryCache.put(fileName,
result); //
key is a unique token, value is the bitmap |
056 |
|
057 |
fileCache.put(fileName,
result); |
058 |
} |
059 |
} |
060 |
|
061 |
private AsyncImageLoader(Context
context){ |
062 |
this .memoryCache
= new MemoryCache(); |
063 |
this .fileCache
= new FileCache(context); |
064 |
} |
065 |
|
066 |
public static AsyncImageLoader
getInstance(Context context){ |
067 |
if (imageLoader
== null ) |
068 |
imageLoader
= new AsyncImageLoader(context); |
069 |
|
070 |
return imageLoader; |
071 |
} |
072 |
|
073 |
public void displayBitmap(ImageView
imageView, String fileName){ |
074 |
//no
pic for this item |
075 |
if (fileName
== null || "" .equals(fileName)) |
076 |
return ; |
077 |
|
078 |
Bitmap
bitmap = getBitmap(fileName); |
079 |
//search
in cache, if there is no such bitmap, launch downloads |
080 |
if (bitmap
!= null ){ |
081 |
imageView.setImageBitmap(bitmap); |
082 |
} |
083 |
else { |
084 |
Log.w(TAG, "Can't
find the file you required." ); |
085 |
new AsyncImageDownloader(imageView,
fileName).execute(); |
086 |
} |
087 |
} |
088 |
|
089 |
public Bitmap
getBitmap(String key){ |
090 |
Bitmap
bitmap = null ; |
091 |
//1.
search memory |
092 |
bitmap
= memoryCache.get(key); |
093 |
|
094 |
//2.
search sdcard |
095 |
if (bitmap
== null ){ |
096 |
File
file = fileCache.getFile(key); |
097 |
if (file
!= null ) |
098 |
bitmap
= BitmapHelper.decodeFile(file, null ); |
099 |
} |
100 |
|
101 |
return bitmap; |
102 |
} |
103 |
|
104 |
public void clearCache(){ |
105 |
if (memoryCache
!= null ) |
106 |
memoryCache.clear(); |
107 |
if (fileCache
!= null ) |
108 |
fileCache.clear(); |
109 |
} |
110 |
}</strong> |
原始碼:
附上原始碼,不過伺服器的原始碼暫時還沒有放出來,先看看客戶端的吧。
https://github.com/ryanhoo/SoftRead
相關文章
- android ListView非同步載入圖片(雙快取)AndroidView非同步快取
- android非同步圖片載入三之handler+執行緒池+訊息佇列模式+快取Android非同步執行緒佇列模式快取
- 安卓快取之LruCache及設計(非同步+快取)圖片載入器LruCacheImageLoader安卓快取非同步
- iOS Cell非同步圖片載入優化,快取機制詳解iOS非同步優化快取
- 圖片三級快取及OOM--android快取OOMAndroid
- 【構建Android快取模組】(二)Memory Cache & File CacheAndroid快取
- Android 視訊縮圖的快取機制和非同步載入Android快取非同步
- Android平滑圖片載入和快取庫 Glide 使用詳解Android快取IDE
- Android 平滑圖片載入和快取庫 Glide 使用詳解Android快取IDE
- Android實現圖片非同步載入操作Android非同步
- Android中圖片的三層快取詳解Android快取
- Android 圖片快取處理Android快取
- Android 圖片載入快取問題:為什麼你的Glide快取沒有起作用?Android快取IDE
- 開源框架——圖片載入和快取方案總結框架快取
- Glide 4.0.0 下之載入本地快取的圖片IDE快取
- Android圖片快取框架GlideAndroid快取框架IDE
- 快取圖片快取
- 圖片快取快取
- Android 圖片載入框架Android框架
- android 載入大量圖片Android
- Android ImageLoader 框架之圖片快取Android框架快取
- Android使用LruCache、DiskLruCache實現圖片快取+圖片瀑布流Android快取
- Android 載入大圖片,不壓縮圖片Android
- android listview 滾動時非同步載入圖片的問題AndroidView非同步
- Android:手把手教你構建 WebView 的快取機制 & 資源預載入方案AndroidWebView快取
- Android 之 遠端圖片獲取和本地快取Android快取
- Android 高效安全載入圖片Android
- Android技術積累:圖片快取管理Android快取
- ListView 之非同步載入圖片亂序View非同步
- ListView效能優化非同步載入圖片View優化非同步
- android Gallery實現非同步載入網路圖片 並只載入當前停止頁面圖Android非同步
- android glide圖片載入框架AndroidIDE框架
- SDWebImage實現圖片展示、快取、清除快取Web快取
- C#中PictureBox非同步載入圖片C#非同步
- Android Volley 原始碼解析(三),圖片載入的實現Android原始碼
- Android ImageLoader框架之圖片載入與載入策略Android框架
- Android應用開發之(利用好圖片快取)Android快取
- Android 基礎之圖片載入(二)Android