Android 非同步載入圖片-LruCache和SD卡或手機快取-三級快取原理載入圖片
非同步載入圖片的例子,網上也比較多,大部分用了HashMap<String, SoftReference<Drawable>> imageCache ,但是現在已經不再推薦使用這種方式了,因為從 Android 2.3 (API Level 9)開始,垃圾回收器會更傾向於回收持有軟引用或弱引用的物件,這讓軟引用和弱引用變得不再可靠。另外,Android 3.0 (API Level 11)中,圖片的資料會儲存在本地的記憶體當中,因而無法用一種可預見的方式將其釋放,這就有潛在的風險造成應用程式的記憶體溢位並崩潰,所以我這裡用得是LruCache來快取圖片,當儲存Image的大小大於LruCache設定的值,系統自動釋放記憶體,這個類是3.1版本中提供的,如果你是在更早的Android版本中開發,則需要匯入android-support-v4的jar包(這裡要注意咯)
為什麼寫這篇文章呢?
因為我之前做的專案中,也有非同步載入圖片,那時候用得是Thread去下載圖片,每次下載圖片都要new Thread去下載,而且還是併發去下載,每次都new 一個執行緒浪費記憶體,老闆說伺服器承受不起這麼多的連線,叫我改成先獲取一張圖片之後再去獲取下一張,這樣子儲存與伺服器的連線為一個,伺服器壓力小了,然後樓主就想到執行緒池,執行緒池很好的幫我們管理併發的問題,併發的問題解決了,可是後面又出問題了,圖片多了就出現OOM(OutOfMemory)異常,之後用了SoftReference,先用SoftReference中獲取圖片,SoftReference沒有就開執行緒去下載,老闆說你為什麼不把圖片在手機上做個快取呢,於是我用了手機快取,大概思路就是先從SoftReference中獲取圖片,如果SoftReference沒有就去手機快取中獲取,手機快取中沒有就開啟先從去下載,然後成功的解決了OOM的問題,前些天老闆要我重構下程式碼,我也覺得之前寫的程式碼耦合性太強,早就想改,然後之前看到guolin的
這篇文章做了哪些方面的優化
- 使用了執行緒池來管理下載任務
- 使用LruCache來快取圖片
- 使用手機來快取圖片
- GridView滑動的時候取消下載任務,靜止的時候進行下載,GridView滑動更加的流暢
- 降低了程式碼的耦合性,結構更加的清晰,便於以後重用
接下來我們先來看看專案的結構
- FileUtils 檔案操作的工具類,提供儲存圖片,獲取圖片,判斷圖片是否存在,刪除圖片的一些方法,這個類比較簡單
- package com.example.asyncimageloader;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.Bitmap.CompressFormat;
- import android.graphics.BitmapFactory;
- import android.os.Environment;
- publicclass FileUtils {
- /**
- * sd卡的根目錄
- */
- privatestatic String mSdRootPath = Environment.getExternalStorageDirectory().getPath();
- /**
- * 手機的快取根目錄
- */
- privatestatic String mDataRootPath = null;
- /**
- * 儲存Image的目錄名
- */
- privatefinalstatic String FOLDER_NAME = "/AndroidImage";
- public FileUtils(Context context){
- mDataRootPath = context.getCacheDir().getPath();
- }
- /**
- * 獲取儲存Image的目錄
- * @return
- */
- private String getStorageDirectory(){
- return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ?
- mSdRootPath + FOLDER_NAME : mDataRootPath + FOLDER_NAME;
- }
- /**
- * 儲存Image的方法,有sd卡儲存到sd卡,沒有就儲存到手機目錄
- * @param fileName
- * @param bitmap
- * @throws IOException
- */
- publicvoid savaBitmap(String fileName, Bitmap bitmap) throws IOException{
- if(bitmap == null){
- return;
- }
- String path = getStorageDirectory();
- File folderFile = new File(path);
- if(!folderFile.exists()){
- folderFile.mkdir();
- }
- File file = new File(path + File.separator + fileName);
- file.createNewFile();
- FileOutputStream fos = new FileOutputStream(file);
- bitmap.compress(CompressFormat.JPEG, 100, fos);
- fos.flush();
- fos.close();
- }
- /**
- * 從手機或者sd卡獲取Bitmap
- * @param fileName
- * @return
- */
- public Bitmap getBitmap(String fileName){
- return BitmapFactory.decodeFile(getStorageDirectory() + File.separator + fileName);
- }
- /**
- * 判斷檔案是否存在
- * @param fileName
- * @return
- */
- publicboolean isFileExists(String fileName){
- returnnew File(getStorageDirectory() + File.separator + fileName).exists();
- }
- /**
- * 獲取檔案的大小
- * @param fileName
- * @return
- */
- publiclong getFileSize(String fileName) {
- returnnew File(getStorageDirectory() + File.separator + fileName).length();
- }
- /**
- * 刪除SD卡或者手機的快取圖片和目錄
- */
- publicvoid deleteFile() {
- File dirFile = new File(getStorageDirectory());
- if(! dirFile.exists()){
- return;
- }
- if (dirFile.isDirectory()) {
- String[] children = dirFile.list();
- for (int i = 0; i < children.length; i++) {
- new File(dirFile, children[i]).delete();
- }
- }
- dirFile.delete();
- }
- }<span style="font-family:Times New Roman;font-size:14px;">
- </span>
- package com.example.asyncimageloader;
- publicclass Images {
- publicfinalstatic String[] imageThumbUrls = new String[] {
- "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s160-c/A%252520Photographer.jpg",
- "https://lh4.googleusercontent.com/--dq8niRp7W4/URquVgmXvgI/AAAAAAAAAbs/-gnuLQfNnBA/s160-c/A%252520Song%252520of%252520Ice%252520and%252520Fire.jpg",
- "https://lh5.googleusercontent.com/-7qZeDtRKFKc/URquWZT1gOI/AAAAAAAAAbs/hqWgteyNXsg/s160-c/Another%252520Rockaway%252520Sunset.jpg",
- "https://lh3.googleusercontent.com/--L0Km39l5J8/URquXHGcdNI/AAAAAAAAAbs/3ZrSJNrSomQ/s160-c/Antelope%252520Butte.jpg",