android 網絡加載圖片,對圖片資源進行優化,而且實現內存雙緩存 + 磁盤緩存

常常會用到 網絡文件 好比查看大圖片數據 資源優化的問題,固然用開源的項目  Android-Universal-Image-Loader  或者 ignition 都是個很好的選擇。java

在這裏把原來 寫過的優化的代碼直接拿出來,通過測試千張圖片效果仍是不錯的。android

免費培訓課:http://www.jinhusns.com/Products/Curriculum/?type=xcj算法

 

工程目錄緩存

 

至於 Activity 就是加載了 1個網格佈局安全

01. /**
02. *   實現 異步加載 和   2級緩存
03. */
04. public class ImagedownActivity extends Activity {
05.  
06. public static String filepath;
07. @Override
08. public void onCreate(Bundle savedInstanceState) {
09. super.onCreate(savedInstanceState);
10. setContentView(R.layout.main);
11. filepath =   this.getCacheDir().getAbsolutePath();
12. GridView gv=(GridView)findViewById(R.id.gridview01);
13. //設置列數
14. gv.setNumColumns(3);
15. //配置適配器
16. gv.setAdapter(new Myadapter(this));
17. }
18.  
19. @Override
20. protected void onDestroy() {
21. // TODO Auto-generated method stub
22. //activity 銷燬時,清除緩存
23. MyImageLoader.removeCache(filepath);
24. super.onDestroy();
25. }
26.  
27. }

 接下來 Myadapter.java(給網格每一個item塞入圖片 )在生成每一個 item 異步請求網絡獲取image服務器

01. public class Myadapter extends BaseAdapter {
02. private Context context;
03. private String  root ="http://192.168.0.100:8080/Android_list/";
04. private String[] URLS;
05. private final MyImageLoader  myImageLoader = new MyImageLoader(context);;
06.  
07. /**
08. * adapter 初始化的時候早一堆數據
09. * 這裏我請求的是本身搭的服務器
10. * @param context
11. */
12. public  Myadapter(Context context){
13. this.context =context;
14. URLS = new String[999];
15. for (int i = 0; i < 999; i++) {
16. URLS[i] = root + (i+1)+".jpg";
17. }  
18. }
19.  
20.  
21. @Override
22. public int getCount() {
23. return URLS.length;
24. }
25.  
26. @Override
27. public Object getItem(int position) {
28. return URLS[position];
29. }
30.  
31. @Override
32. public long getItemId(int position) {
33. return URLS[position].hashCode();
34. }
35.  
36.  
37.  
38. @Override
39. public View getView(int position, View view, ViewGroup parent) {
40. ImageView imageView;
41. if(view==null){
42. imageView=new ImageView(context);
43. imageView.setLayoutParams(new GridView.LayoutParams(200,190));
44. imageView.setAdjustViewBounds(false);
45. imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
46. imageView.setPadding(5, 5, 5, 5);
47. }else{
48. imageView=(ImageView)view;
49. }
50. myImageLoader.downLoad(URLS[position], (ImageView)imageView , context);
51. return imageView;
52. }
53. }

 MyImageLoader.java網絡

001. public class MyImageLoader { 
002.  
003. //最大內存 
004. final static int memClass = (int) Runtime.getRuntime().maxMemory();   
005. private Context context; 
006.  
007. // 是否緩存到硬盤 
008. private boolean  diskcache = true
009.  
010. // 定義一級 緩存的圖片數 
011. private static final int catch_num = 10
012.  
013. // 定義二級緩存 容器  軟引用 
014. private static ConcurrentHashMap<String, SoftReference<Bitmap>> current_hashmap = new ConcurrentHashMap<String, SoftReference<Bitmap>>(); 
015.  
016. // 定義一級緩存容器  強引用       (catch_num ,0.75f,true) 默認參 數                                                                                                                        2.加載因子默認        3.排序模式 true 
017. private static LinkedHashMap<String, Bitmap> link_hashmap = new LinkedHashMap<String, Bitmap>(catch_num ,0.75f,true) { 
018.  
019. // 必須實現的方法 
020. protected boolean removeEldestEntry(java.util.Map.Entry<String, Bitmap> eldest) { 
021. /** 當一級緩存中 圖片數量大於 定義的數量 放入二級緩存中
022. */ 
023. if (this.size() > catch_num) { 
024. // 軟鏈接的方法 存進二級緩存中 
025. current_hashmap.put(eldest.getKey(), new SoftReference<Bitmap>( 
026. eldest.getValue())); 
027. //緩存到本地 
028. cancheToDisk(eldest.getKey(),eldest.getValue() ); 
029.  
030. return true
031.
032. return false
033. }; 
034. }; 
035.  
036. public MyImageLoader(Context context) { 
037.  
038.
039.  
040.  
041. /**   
042. *  外部調用此方法   進行下載圖片  
043. */ 
044. public void downLoad(String key , ImageView imageView,Context context){ 
045. // 先從緩存中找   。   
046. context = this.context; 
047.  
048. Bitmap bitmap = getBitmapFromCache(key); 
049. if( null!= bitmap){  
050. imageView.setImageBitmap(bitmap); 
051. cancleDownload(key, imageView);         //取消下載 
052. return
053. }     
054.  
055. // 緩存中 沒有  把當前的 imageView 給他 獲得 task  
056. if(cancleDownload(key, imageView)){     //沒有任務進行。,。。開始下載 
057. ImageDownloadTask task = new ImageDownloadTask(imageView); 
058. Zhanwei_Image  zhanwei_image = new Zhanwei_Image(task); 
059. //先把佔位的圖片放進去 
060. imageView.setImageDrawable(zhanwei_image); 
061. // task執行任務 
062. task.execute(key);  
063.
064.
065.  
066.  
067. /** 此方法 用於優化  : 用戶直接 翻到 哪一個 就先加載 哪一個、
068. * @param key                - URL
069. * @param imageView          - imageView
070. *  core: 給當前的 imageView 獲得給他下載的 task
071. */ 
072.  
073. private boolean cancleDownload(String key,ImageView imageView){ 
074. // 給當前的 imageView 獲得給他下載的 task 
075. ImageDownloadTask task = getImageDownloadTask(imageView); 
076. if(null != task){ 
077. String down_key = task.key; 
078. if( null == down_key || !down_key.equals(key)){ 
079. task.cancel(true);        // imageview 和 url 的key不同       取消下載    
080. }else
081. return false;      //正在下載:  
082. }   
083.
084. return true;            //沒有正在下載 
085.
086.  
087.  
088.  
089. //  public void getThisProcessMemeryInfo() { 
090. //        int pid = android.os.Process.myPid(); 
091. //        android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(new int[] {pid}); 
092. //        System.out.println("本應用當前使用了" + (float)memoryInfoArray[0].getTotalPrivateDirty() / 1024 + "mb的內存"); 
093. //    } 
094.  
095.  
096.  
097. /**
098. * 從緩存中獲得 圖片的方法 1.先從一級 緩存找 linkhashmap 不是線程安全的 必需要加同步
099. */ 
100. public Bitmap getBitmapFromCache(String key) { 
101. //1.先在一級緩存中找 
102. synchronized (link_hashmap) { 
103. Bitmap bitmap = link_hashmap.get(key); 
104. if (null != bitmap) { 
105. link_hashmap.remove(key); 
106. // 按照 LRU是Least Recently Used 近期最少使用算法 內存算法 就近 就 原則 放到首位 
107. link_hashmap.put(key, bitmap); 
108. System.out.println(" 在緩存1中找圖片了 =" +key); 
109. return bitmap; 
110.
111.
112.  
113. // 2. 到二級 緩存找 
114. SoftReference<Bitmap> soft = current_hashmap.get(key); 
115. if (soft != null) { 
116. //獲得 軟鏈接 中的圖片 
117. Bitmap soft_bitmap = soft.get();       
118. if (null != soft_bitmap) { 
119. System.out.println(" 在緩存2中找圖片了 =" +key); 
120. return soft_bitmap; 
121.
122. } else
123. // 沒有圖片的話 把這個key刪除 
124. current_hashmap.remove(key);       
125.
126.  
127.  
128. //3.都沒有的話去從外部緩存文件讀取 
129. if(diskcache){ 
130. Bitmap bitmap = getBitmapFromFile(key); 
131. if(bitmap!= null){ 
132. link_hashmap.put(key, bitmap);   //將圖片放到一級緩存首位 
133. return bitmap; 
134.
135.
136.  
137. return null
138.
139.  
140.  
141. /**
142. * 緩存到本地文件
143. * @param key
144. * @param bitmap
145. */ 
146. public static void cancheToDisk(String key ,Bitmap bitmap ){ 
147. //2.緩存bitmap至/data/data/packageName/cache/文件夾中 
148. try
149. String fileName = getMD5Str(key); 
150. String filePath = ImagedownActivity.filepath + "/" + fileName; 
151. System.out.println("緩存到本地===" + filePath); 
152. FileOutputStream fos = new FileOutputStream(filePath); 
153. bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); 
154.  
155. } catch (Exception e) { 
156.  
157.
158.
159.  
160.  
161. /**
162. * 從外部文件緩存中獲取bitmap
163. * @param url
164. * @return
165. */ 
166. private Bitmap getBitmapFromFile(String url){ 
167. Bitmap bitmap = null
168. String fileName = getMD5Str(url); 
169. if(fileName == null){ 
170. return null
171. }    
172. String filePath = ImagedownActivity.filepath + "/" + fileName;       
173. try
174. FileInputStream fis = new FileInputStream(filePath); 
175. bitmap = BitmapFactory.decodeStream(fis); 
176. System.out.println("在本地緩存中找到圖片==="+ filePath); 
177. } catch (FileNotFoundException e) { 
178. System.out.println("getBitmapFromFile==="+ e.toString()); 
179. e.printStackTrace(); 
180. bitmap = null
181.
182. return bitmap; 
183.
184.  
185.  
186.  
187. /**
188. * 清理文件緩存
189. * @param dirPath
190. * @return
191. */ 
192. public static boolean removeCache(String dirPath) { 
193. File dir = new File(dirPath); 
194. File[] files = dir.listFiles(); 
195. if(files == null || files.length == 0) { 
196. return true
197.
198. int dirSize = 0
199. //這裏刪除全部的緩存 
200. int all_ = (int) ( 1 * files.length + 1); 
201. //對files 進行排序 
202. Arrays.sort(files, new FileLastModifiedSort()); 
203. for (int i = 0; i < all_ ; i++) { 
204. files[i].delete(); 
205.
206. return true
207.
208.  
209.  
210. /**
211. * 根據文件最後修改時間進行排序
212. */ 
213. private static class FileLastModifiedSort implements Comparator<File> { 
214. @Override 
215. public int compare(File lhs, File rhs) { 
216. if(lhs.lastModified() > rhs.lastModified()) { 
217. return 1
218. } else if(lhs.lastModified() == rhs.lastModified()) { 
219. return 0
220. } else
221. return -1
222.
223.
224.
225.  
226.  
227. /**  
228. * MD5 加密  
229. */    
230. private static String getMD5Str(String str) {    
231. MessageDigest messageDigest = null;    
232. try {    
233. messageDigest = MessageDigest.getInstance("MD5");    
234. messageDigest.reset();    
235. messageDigest.update(str.getBytes("UTF-8"));    
236. } catch (NoSuchAlgorithmException e) {    
237. System.out.println("NoSuchAlgorithmException caught!");    
238. return null
239. } catch (UnsupportedEncodingException e) {    
240. e.printStackTrace(); 
241. return null
242. }    
243.  
244. byte[] byteArray = messageDigest.digest();    
245. StringBuffer md5StrBuff = new StringBuffer();    
246. for (int i = 0; i < byteArray.length; i++) {                
247. if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)    
248. md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));    
249. else    
250. md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));    
251. }    
252. return md5StrBuff.toString();    
253. }   
254.  
255.  
256. // ------------------------ 異步加載---------------------------- 
257. /**
258. *  佔位的 圖片 或者 顏色      用來綁定 相應的圖片
259. */   
260. class Zhanwei_Image extends ColorDrawable{ 
261. //裏面存放 相應 的異步 處理時加載好的圖片 ----- 相應的 task 
262. private final WeakReference<ImageDownloadTask>  taskReference; 
263. public Zhanwei_Image(ImageDownloadTask task){    
264. super(Color.BLUE); 
265. taskReference = new WeakReference<MyImageLoader.ImageDownloadTask>(task);  
266. }   
267. // 返回去這個 task 用於比較 
268. public ImageDownloadTask getImageDownloadTask(){ 
269. return taskReference.get(); 
270.
271.
272.  
273.  
274. // 根據 給 的 iamgeView、 獲得裏面的 task  用於和當前的 task比較是否是同1個 
275. private ImageDownloadTask getImageDownloadTask(ImageView imageView){ 
276. if( null != imageView){ 
277. Drawable drawable = imageView.getDrawable();     
278. if( drawable instanceof Zhanwei_Image) 
279. return ((Zhanwei_Image)drawable).getImageDownloadTask(); 
280.  
281.
282. return null
283.
284.  
285.  
286.  
287. /**
288. * 把圖片 添加到緩存中
289. */ 
290. public void addBitmap(String key, Bitmap bitmap) { 
291. if (null != bitmap) { 
292. synchronized (link_hashmap) {         // 添加到一級 緩存中 
293. link_hashmap.put(key, bitmap); 
294.
295.
296.
297.  
298.  
299. /** 在後臺 加載每一個圖片
300. *  第一個參數 第2個要進度條不 第三個返回結果 bitmap
301. */ 
302. class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> { 
303.  
304. private String key; 
305. private WeakReference<ImageView> imgViReference; 
306.  
307. public ImageDownloadTask(ImageView imageView) { 
308. //imageView 傳進來 。。要給哪一個iamgeView加載圖片 
309. imgViReference = new WeakReference<ImageView>( 
310. imageView); 
311.
312.  
313. @Override 
314. protected Bitmap doInBackground(String... params){ 
315. key = params[0]; 
316. //調用下載函數 根據 url 下載       
317. return downloadBitmap(key); 
318.
319.  
320. @Override 
321. protected void onPostExecute(Bitmap result) { 
322. if(isCancelled()){ 
323. result = null
324.
325.  
326. System.out.println("result=="+ result.getByteCount()+"---memClassmemery="+memClass); 
327.  
328. if(null!= result){ 
329. //保存到緩存中 
330. addBitmap(key, result); 
331. ImageView  imageView = imgViReference.get(); 
332. if( null != imageView){   
333. //向 imageView 裏面放入 bitmap          
334. ImageDownloadTask task = getImageDownloadTask(imageView); 
335.  
336. /**
337. *  判斷 是否是 同一個 task( )
338. *  若是當前這個 task  ==  imageView 裏面的那個 task 就是同1個
339. */ 
340. if( this == task ){ 
341. imageView.setImageBitmap(result); 
342.  
343.
344.
345.
346.
347.
348.  
349.  
350. /**
351. * 鏈接網絡 客戶端 下載圖片
352. */ 
353. private Bitmap downloadBitmap(String url) { 
354.  
355. final HttpClient client = AndroidHttpClient.newInstance("Android"); 
356. final HttpGet getRequest = new HttpGet(url);  
357. try
358. HttpResponse response = client.execute(getRequest); 
359. final int statusCode = response.getStatusLine().getStatusCode(); 
360.  
361. if (statusCode != HttpStatus.SC_OK) { 
362.  
363. Log.w("ImageDownloader", "Error " + statusCode + " while retrieving bitmap from " + url); 
364. return null
365.
366.  
367. final HttpEntity entity = response.getEntity(); 
368. if (entity != null) { 
369. InputStream inputStream = null
370. try
371.  
372. inputStream = entity.getContent();                  
373. /**
374. *  1.沒有壓縮直接將生成的bitmap返回去
375. */ 
376. //                  return BitmapFactory.decodeStream(inputStream); 
377.  
378. /**
379. *  2.獲得data後在這裏把圖片進行壓縮
380. */ 
381. byte[] data = StreamTool.read(inputStream);  
382. return  BitmapManager.scaleBitmap(context, data, 0.3f); 
383. //                   return BitmapFactory.decodeStream(new FlushedInputStream(inputStream)); 
384. } finally
385. if (inputStream != null) { 
386. inputStream.close(); 
387.
388. entity.consumeContent(); 
389.
390.
391. } catch (IOException e) { 
392. getRequest.abort(); 
393. } catch (IllegalStateException e) { 
394. getRequest.abort(); 
395. } catch (Exception e) { 
396. getRequest.abort(); 
397. } finally
398. if ((client instanceof AndroidHttpClient)) { 
399. ((AndroidHttpClient) client).close(); 
400.
401.
402. return null
403.
404.  
405. }

 StreamTool.java併發

01. public class StreamTool { 
02.  
03. public static  byte[] read(InputStream in) throws Exception{ 
04. ByteArrayOutputStream  out_byte = new ByteArrayOutputStream(); 
05. byte[] buff = new byte[1024]; 
06. int len=0
07. while((len = in.read(buff))!= -1){ 
08. //寫到內存中  字節流 
09. out_byte.write( buff, 0 , len); 
10. }    
11. out_byte.close();    
12. // 把內存數據返回 
13. return  out_byte.toByteArray();  
14.
15. }

 BitmapManager.java ( 這個類裏面對 網絡資源的圖片 進行了優化)app

001. public class BitmapManager {
002.  
003. /**
004. * 按屏幕適配Bitmap
005. */
006. public static Bitmap scaleBitmap(Context context, byte[] data , float percent) {
007.  
008. //這裏我不獲取了,假設是下面這個分辨率
009. int screenWidth =   540;
010. int screenrHeight = 950;
011. //設置 options
012. BitmapFactory.Options options = new BitmapFactory.Options();
013. /**
014. *  BitmapFactory.Options這個類,有一個字段叫作 inJustDecodeBounds.SDK中對這個成員的說明是這樣的:
015. *  If set to true, the decoder will return null (no bitmap), but the out…
016. *  也就是說,若是咱們把它設爲true,那麼BitmapFactory.decodeFile(String path, Options opt)並不會真的返回一個Bitmap給你,
017. *  它僅僅會把它的寬,高取回來給你,這樣就不會佔用太多的內存,也就不會那麼頻繁的發生OOM了。
018. */
019. options.inJustDecodeBounds = true;
020.  
021. //讀取
022. Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
023.  
024. int imgWidth = options.outWidth;
025. int imgHeight = options.outHeight;
026.  
027. //若是比你設置的寬高大  就進行縮放,
028. if(imgWidth > screenWidth * percent || imgHeight > screenrHeight * percent) {
029. options.inSampleSize = calculateInSampleSize(options, screenWidth, screenrHeight, percent);
030. }
031.  
032.  
033. /**
034. * If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller
035. * to query the bitmap without having to allocate the memory for its pixels.
036. *
037. * 若是設置成 true,這個編碼將會返回1個null , 可是那個區域仍將被設置(也就是存在),容許(調用者)去查詢那個沒有分配 內存的像素  bitmap
038. */
039. options.inJustDecodeBounds = false;
040.  
041. /**
042. *  Android的Bitmap.Config給出了bitmap的一個像素所對應的存儲方式,
043. *  有RGB_565,ARGB_8888,ARGB_4444,ALPHA_8四種。RGB_565表示的是紅綠藍三色分別用5,6,5個比特來存儲,
044. *  一個像素佔用了5+6+5=16個比特。ARGB_8888表示紅綠藍和半透明分別用8,8,8,8個比特來存儲,
045. *  一個像素佔用了8+8+8+8=32個比特。這樣的話若是圖片是以RGB_8888讀入的,那麼佔用內存的大小將是RGB_565讀入方式的2倍。
046. *  一般咱們給Imagview加載圖片是經過setDrawable或者在xml文件中用android:src來設置
047. *  默認的加載圖片大小的方式是以RGB_8888讀入的。
048. *
049. */
050. options.inPreferredConfig = Bitmap.Config.RGB_565;
051.  
052. /**
053. * If this is set to true, then the resulting bitmap will allocate its pixels such that they can be purged
054. * if the system needs to reclaim memory.
055. *
056. * 若是設置成 true, 這個結果bitmap 將會被分配像素,這樣他們就能被 系統回收了,當系統須要回收內存的時候
057. */
058. options.inPurgeable = true;
059.  
060. /**
061. * This field works in conjuction with inPurgeable.
062. * 這個方法是在   inPurgeable 的基礎上工做的
063. */
064. options.inInputShareable = true;
065.  
066.  
067. bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
068.  
069. System.out.println("data==="+  data.length +"  change == bitmap byte "+ bitmap.getByteCount());
070. return bitmap;
071. }
072.  
073.  
074.  
075. //                                                    options       reqWidth 屏幕寬      reqHeight屏幕高      你的view是屏幕的多大
076. public static int calculateInSampleSize(BitmapFactory.Options options, int screenWidth, int screenHeight ,float percent) {
077.  
078. // 原始圖片寬高
079. final int height = options.outHeight;
080. final int width = options.outWidth;
081. // 倍數
082. int inSampleSize = 1;
083.  
084. if (height > screenHeight * percent || width > screenWidth * percent) {
085.  
086. // 計算目標寬高與原始寬高的比值
087. final int inSampleSize_h = Math.round((float) height / (float)( screenHeight * percent));
088.  
089. final int inSampleSize_w = Math.round((float) width / (float)( screenWidth * percent));
090.  
091. // 選擇兩個比值中較小的做爲inSampleSize的
092. inSampleSize = inSampleSize_h < inSampleSize_w ? inSampleSize_h : inSampleSize_w;
093.  
094. System.out.println("inSampleSize===="+ inSampleSize);
095. //
096. if(inSampleSize < 1) {
097. inSampleSize = 1;
098. }
099. }
100. //簡單說這個數字就是 縮小爲原來的幾倍,根據你的image須要佔屏幕多大動態算的(好比你用的權重設置layout)
101. return inSampleSize;
102. }
103. }

 這個是代碼輸出的最多給這個進程分配的內存 128M異步

能夠看到我上面的bitmapManager 裏面有個   options.inPreferredConfig   註釋寫的很清楚,能夠上去看一下,接下來貼幾種格式的效果圖

rgb565  和  argb_444  所佔的內存              (54000)

 

看一下 argb_8888                    (  108000)

 

固然可能仔細看的人會看到我一開始截的 鳴人的效果圖 上半部分 和 下半部分的顏色會有點問題。上面的rgb_565 生成的,和原圖色彩可能會有點出入。

可是內存真心少了一半,因此各類取捨就看我的了,代碼註釋都謝的很清楚了。

 

至於 : MyImageLoaderLru.java  其實就是    MyImageLoader.java

先貼出代碼不一樣地方的代碼 : 就是在強引用的地方  把  LinkedHashMap 換成了 LruCache

 

 
01. // 獲取單個進程可用內存的最大值 
02. // 方式一:使用ActivityManager服務(計量單位爲M) 
03. /*int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();*/ 
04. // 方式二:使用Runtime類(計量單位爲Byte) 
05. final static int memClass = (int) Runtime.getRuntime().maxMemory(); 
06. // 3. 定義一級緩存容器  強引用       (catch_num /2,0.75f,true) 默認參 數                                                                                                                        2.加載因子默認        3.排序模式 true
07. final static int  max = memClass/5;
08.  
09. // LruCache 用強引用將  圖片放入     LinkedHashMap
10. private static LruCache<String, Bitmap> lrucache = new LruCache<String, Bitmap>(max) {
11. protected int sizeOf(String key, Bitmap value) { 
12. if(value != null) { 
13. // 計算存儲bitmap所佔用的字節數 
14. return value.getRowBytes() * value.getHeight(); 
15. } else
16. return 0
17.
18.
19.  
20. @Override 
21. protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) { 
22. if(oldValue != null) { 
23. // 當硬引用緩存容量已滿時,會使用LRU算法將最近沒有被使用的圖片轉入軟引用緩存 
24. current_hashmap.put(key, new SoftReference<Bitmap>(oldValue)); 
25.
26.
27. };

1. 強引用:LruCache 後面再說,其實他內的內部封裝的就是1個 LinkedHashMap 。LinkedHashMap 是線程不安全的,因此上面都會用到同步。

2. 軟引用:ConcurrentHashMap 是線程安全的,而且支持高併發頗有效率,這個後面也會說到,爲何要用 軟引用 SoftReference,這個是在系統將要oom時,就會回收

                    軟引用的對象資源,因此纔會用到他,防止程序出異常 。

3. 磁盤緩存: 這個常常會看到網易新聞等,應用有些界面你看了不少圖片,往上翻不少, 其實沒有再次訪問網絡,會將部分image緩存在sdcard裏。

4. 其中1個優化: 當好比用戶快速滑動到 最底部,實際上是最早加載顯示給用戶的部分的內容的,這樣就是用戶看到哪加載哪,1個是快,1個是避免資源浪費。

 

原理: 當用戶進入界面加載圖片 ,首先會從1級緩存強引用中找,找不到回去2級緩存軟引用中找,找不到再去sdcard中找,再找不到纔會去請求網絡加載資源。

            固然sdcard的緩存 看我的需求是否須要。

 

注: android 4.0 後 對 SoftReference 的回收機制進行了改變,因此你是能夠不用 2級緩存的,直接去掉就行了。

          只要控制好你的 lrucache 或者 linkedhashmap就行了。

免費培訓課:http://www.jinhusns.com/Products/Curriculum/?type=xcj

相關文章
相關標籤/搜索