圖片的三級緩存基礎(chǔ)
1.圖片緩存優(yōu)先級:Bitmap優(yōu)于手機本地的圖片文件優(yōu)于服務(wù)器端的圖片文件
一級緩存:內(nèi)存緩存,緩存的是bitmap對象(這些對象在內(nèi)存如何存儲呢?一般而言有兩種方式:List和Map,List根據(jù)下標(biāo)來得到對象,Map根據(jù)Key得到對象,實際圖片存儲都是用Map)。
二級緩存:本地(SD卡)緩存,緩存的是圖片文件,/storage/sdcard/Android/data/packageName/files/圖片文件名(xxx.jpg)
三級緩存:遠程服務(wù)器緩存,緩存的是圖片文件,遠程服務(wù)器上的應(yīng)用中
2.如何使用三級緩存?-----如何根據(jù)圖片的URL動態(tài)顯示圖片?
String imagePath = http://192.168.10.165:8080//L05_Web/images/f10.jpg和ImageView對象
1)。根據(jù)Url從一級緩存中取對應(yīng)的bitmap對象
如果有,顯示(結(jié)束)
如果沒有,進入2
2)。從二級緩存中查找:得到文件名,并在sd卡的緩存目錄下加載對應(yīng)的圖片得到Bitmap對象
如果有:顯示,緩存到一級緩存中(結(jié)束)
如果沒有,進入3
3)。顯示代表提示正在加載的圖片,啟動分線程聯(lián)網(wǎng)請求得到Bitmap對象
如果沒有:顯示提示錯誤的圖片(結(jié)束)
如果有:
顯示
緩存到一級緩存
緩存到二級緩存
1 /** 2 String iamgePath = http://192.168.10.165:8080//L05_Web/images/f10.jpg和ImageView對象 3 1). 根據(jù)url從一級緩存中取對應(yīng)的bitmap對象 4 如果有, 顯示(結(jié)束) 5 如果沒有, 進入2) 6 2). 從二級緩存中查找: 得到文件名并在sd卡的緩存目錄下加載對應(yīng)的圖片得到Bitmap對象 7 如果有: 顯示, 緩存到一級緩存中(結(jié)束) 8 如果沒有, 進入3) 9 3). 顯示代表提示正在加載的圖片, 啟動分線程聯(lián)網(wǎng)請求得到Bitmap對象 10 如果沒有: 顯示提示錯誤的圖片(結(jié)束) 11 如果有: 12 顯示 13 緩存到一級緩存 14 緩存到二級緩存 15 */ 16 public class ImageLoader { 17 18 private Context context; 19 private int loadingImageRes; 20 private int errorImageRes; 21 22 public ImageLoader(Context context, int loadingImageRes, int errorImageRes) { 23 super(); 24 this.context = context; 25 this.loadingImageRes = loadingImageRes; 26 this.errorImageRes = errorImageRes; 27 } 28 29 //用于緩存bitmap的容器對象 30 private Map<String, Bitmap> cacheMap = new HashMap<String, Bitmap>(); 31 32 /** 33 * 加載圖片并顯示 34 * @param imagePath 35 * @param imageView 36 */ 37 public void loadImage(String imagePath, ImageView imageView) { 38 39 //將需要顯示的圖片url保存到視圖上 40 imageView.setTag(imagePath); 41 42 /* 43 1). 根據(jù)url從一級緩存中取對應(yīng)的bitmap對象 44 如果有, 顯示(結(jié)束) 45 如果沒有, 進入2) 46 */ 47 Bitmap bitmap = getFromFirstCache(imagePath); 48 if(bitmap!=null) { 49 imageView.setImageBitmap(bitmap); 50 return; 51 } 52 /* 53 2). 從二級緩存中查找: 得到文件名并在sd卡的緩存目錄下加載對應(yīng)的圖片得到Bitmap對象 54 如果有: 顯示, 緩存到一級緩存中(結(jié)束) 55 如果沒有, 進入3) 56 57 /storage/sdcard/Android/data/packageName/files/圖片文件名(xxx.jpg) 58 */ 59 bitmap = getFromSecondCache(imagePath); 60 if(bitmap!=null) { 61 imageView.setImageBitmap(bitmap); 62 cacheMap.put(imagePath, bitmap); 63 return; 64 } 65 66 /* 67 3). 顯示代表提示正在加載的圖片, 啟動分線程聯(lián)網(wǎng)請求得到Bitmap對象 68 如果沒有: 顯示提示錯誤的圖片(結(jié)束) 69 如果有: 70 緩存到一級緩存(分線程) 71 緩存到二級緩存(分線程) 72 顯示(主線程) 73 74 */ 75 76 loadBitmapFromThirdCache(imagePath, imageView); 77 } 78 79 /** 80 * 根據(jù)圖片url從三級緩存中取對應(yīng)的bitmap對象并顯示 81 * @param imagePath 82 * @param imageView 83 * AsyncTask 84 * loadBitmapFromThirdCache("../b.jpg", imageView) 85 * loadBitmapFromThirdCache("../f.jpg", imageView)--->imageView.setTag("../f.jpg") 86 */ 87 private void loadBitmapFromThirdCache(final String imagePath, final ImageView imageView) { 88 new AsyncTask<Void, Void, Bitmap>() { 89 protected void onPreExecute() { 90 imageView.setImageResource(loadingImageRes); 91 } 92 93 //聯(lián)網(wǎng)請求得到bitmap對象 94 @Override 95 protected Bitmap doInBackground(Void... params) { 96 //在分線程執(zhí)行, 可能需要等待一定時間才會執(zhí)行 97 //在等待的過程中imageView中的tag值就有可能改變了 98 //如果改變了, 就不應(yīng)該再去加載圖片(此圖片此時不需要顯示) 99 100 Bitmap bitmap = null; 101 try { 102 103 //在準備請求服務(wù)器圖片之前, 判斷是否需要加載 104 String newImagePath = (String) imageView.getTag(); 105 if(newImagePath!=imagePath) {//視圖已經(jīng)被復(fù)用了 106 return null; 107 } 108 109 //得到連接 110 URL url = new URL(imagePath); 111 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 112 //設(shè)置 113 connection.setConnectTimeout(5000); 114 connection.setReadTimeout(5000); 115 //連接 116 connection.connect(); 117 //發(fā)請求讀取返回的數(shù)據(jù)并封裝為bitmap 118 int responseCode = connection.getResponseCode(); 119 if(responseCode==200) { 120 InputStream is = connection.getInputStream();//圖片文件流 121 //將is封裝為bitmap 122 bitmap = BitmapFactory.decodeStream(is); 123 is.close(); 124 125 if(bitmap!=null) { 126 //緩存到一級緩存(分線程) 127 cacheMap.put(imagePath, bitmap); 128 //緩存到二級緩存(分線程) 129 // /storage/sdcard/Android/data/packageName/files/ 130 String filesPath = context.getExternalFilesDir(null).getAbsolutePath(); 131 // http://192.168.10.165:8080//L05_Web/images/f10.jpg 132 String fileName = imagePath.substring(imagePath.lastIndexOf("/")+1);// f10.jpg 133 String filePath = filesPath+"/"+fileName; 134 bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(filePath)); 135 } 136 } 137 connection.disconnect(); 138 } catch (Exception e) { 139 e.printStackTrace(); 140 } 141 142 143 return bitmap; 144 } 145 146 protected void onPostExecute(Bitmap bitmap) {//從聯(lián)網(wǎng)請求圖片到得到圖片對象需要一定的時間, 視圖可能被復(fù)用了,不需要顯示 147 //在主線程準備顯示圖片之前, 需要判斷是否需要顯示 148 String newImagePath = (String) imageView.getTag(); 149 if(newImagePath!=imagePath) {//視圖已經(jīng)被復(fù)用了 150 return; 151 } 152 153 //如果沒有: 顯示提示錯誤的圖片(結(jié)束) 154 if(bitmap==null) { 155 imageView.setImageResource(errorImageRes); 156 } else {//如果有, 顯示 157 imageView.setImageBitmap(bitmap); 158 } 159 } 160 }.execute(); 161 } 162 163 /** 164 * 根據(jù)圖片url從二級緩存中取對應(yīng)的bitmap對象 165 * @param imagePath 166 * @return 167 */ 168 private Bitmap getFromSecondCache(String imagePath) { 169 170 // /storage/sdcard/Android/data/packageName/files/ 171 String filesPath = context.getExternalFilesDir(null).getAbsolutePath(); 172 // http://192.168.10.165:8080//L05_Web/images/f10.jpg 173 String fileName = imagePath.substring(imagePath.lastIndexOf("/")+1);// f10.jpg 174 String filePath = filesPath+"/"+fileName; 175 176 return BitmapFactory.decodeFile(filePath); 177 } 178 179 /** 180 * 根據(jù)圖片url從一級緩存中取對應(yīng)的bitmap對象 181 * @param imagePath 182 * @return 183 */ 184 private Bitmap getFromFirstCache(String imagePath) { 185 return cacheMap.get(imagePath); 186 } 187 }
運行效果:
但是,圖片一直在變換,并不固定。
視頻學(xué)習(xí)地址:http://www.gulixueyuan.com/course/112/task/1732/show
圖片三級緩存進階:https://blog.csdn.net/lovoo/article/details/51456515
浙公網(wǎng)安備 33010602011771號