硅谷新聞9--圖片三級(jí)緩存
1.三級(jí)緩存設(shè)計(jì)步驟:
* 從內(nèi)存中取圖片
* 從本地文件中取圖片
向內(nèi)存中保持一份
* 請(qǐng)求網(wǎng)絡(luò)圖片,獲取圖片,顯示到控件上
向內(nèi)存存一份
向本地文件中存一份
1 package com.atguigu.beijingnews.utils; 2 3 import android.graphics.Bitmap; 4 import android.os.Handler; 5 6 public class BitmapCacheUtils { 7 8 /** 9 * 網(wǎng)絡(luò)緩存工具類(lèi) 10 */ 11 private NetCacheUtils netCacheUtils; 12 13 /** 14 * 本地緩存工具類(lèi) 15 */ 16 17 private LocalCacheUtils localCacheUtils; 18 19 /** 20 內(nèi)存緩存工具類(lèi) 21 */ 22 private MemoryCacheUtils memoryCacheUtils; 23 24 public BitmapCacheUtils(Handler handler) { 25 memoryCacheUtils = new MemoryCacheUtils(); 26 localCacheUtils = new LocalCacheUtils(memoryCacheUtils); 27 netCacheUtils = new NetCacheUtils(handler,localCacheUtils,memoryCacheUtils); 28 29 } 30 31 32 /** 33 * 三級(jí)緩存設(shè)計(jì)步驟: 34 * * 從內(nèi)存中取圖片 35 * * 從本地文件中取圖片 36 * 向內(nèi)存中保持一份 37 * * 請(qǐng)求網(wǎng)絡(luò)圖片,獲取圖片,顯示到控件上,Hanlder,postion 38 * * 向內(nèi)存存一份 39 * * 向本地文件中存一份 40 * 41 * @param imageUrl 42 * @param position 43 * @return 44 */ 45 public Bitmap getBitmap(String imageUrl, int position) { 46 //1.從內(nèi)存中取圖片 47 if (memoryCacheUtils != null) { 48 Bitmap bitmap = memoryCacheUtils.getBitmapFromUrl(imageUrl); 49 if (bitmap != null) { 50 LogUtil.e("內(nèi)存加載圖片成功=="+position); 51 return bitmap; 52 } 53 } 54 55 //2.從本地文件中取圖片 56 if (localCacheUtils != null) { 57 Bitmap bitmap = localCacheUtils.getBitmapFromUrl(imageUrl); 58 if (bitmap != null) { 59 LogUtil.e("本地加載圖片成功=="+position); 60 return bitmap; 61 } 62 } 63 64 //3.請(qǐng)求網(wǎng)絡(luò)圖片 65 netCacheUtils.getBitmapFomNet(imageUrl, position); 66 return null; 67 } 68 }
2.網(wǎng)絡(luò)緩存
線程池類(lèi)Executors的使用
public static ExecutorService newCachedThreadPool()
創(chuàng)建一個(gè)可根據(jù)需要?jiǎng)?chuàng)建新線程的線程池,但是在以前構(gòu)造的線程可用時(shí)將重用它們。對(duì)于執(zhí)行很多短期異步任務(wù)的程序而言,這些線程池通常可提高程序性能。調(diào)用 execute 將重用以前構(gòu)造的線程(如果線程可用)。如果現(xiàn)有線程沒(méi)有可用的,則創(chuàng)建一個(gè)新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。因此,長(zhǎng)時(shí)間保持空閑的線程池不會(huì)使用任何資源。注意,可以使用 ThreadPoolExecutor 構(gòu)造方法創(chuàng)建具有類(lèi)似屬性但細(xì)節(jié)不同(例如超時(shí)參數(shù))的線程池。
public static ExecutorService newFixedThreadPool(int nThreads)
創(chuàng)建一個(gè)可重用固定線程數(shù)的線程池,以共享的無(wú)界隊(duì)列方式來(lái)運(yùn)行這些線程。在任意點(diǎn),在大多數(shù) nThreads 線程會(huì)處于處理任務(wù)的活動(dòng)狀態(tài)。如果在所有線程處于活動(dòng)狀態(tài)時(shí)提交附加任務(wù),則在有可用線程之前,附加任務(wù)將在隊(duì)列中等待。如果在關(guān)閉前的執(zhí)行期間由于失敗而導(dǎo)致任何線程終止,那么一個(gè)新線程將代替它執(zhí)行后續(xù)的任務(wù)(如果需要)。在某個(gè)線程被顯式地關(guān)閉之前,池中的線程將一直存在。
1 package com.atguigu.beijingnews.utils; 2 3 import android.graphics.Bitmap; 4 import android.graphics.BitmapFactory; 5 import android.os.Handler; 6 import android.os.Message; 7 8 import java.io.IOException; 9 import java.io.InputStream; 10 import java.net.HttpURLConnection; 11 import java.net.URL; 12 import java.util.concurrent.ExecutorService; 13 import java.util.concurrent.Executors; 14 15 public class NetCacheUtils { 16 17 /** 18 * 請(qǐng)求圖片成功 19 */ 20 public static final int SUCESS = 1; 21 /** 22 * 請(qǐng)求圖片失敗 23 */ 24 public static final int FAIL = 2; 25 private final Handler handler; 26 /** 27 * 本地緩存工具類(lèi) 28 */ 29 private final LocalCacheUtils localCacheUtils; 30 /** 31 * 內(nèi)存緩存工具類(lèi) 32 */ 33 private final MemoryCacheUtils memoryCacheUtils; 34 /** 35 * 線程池類(lèi) 36 */ 37 private ExecutorService service; 38 39 public NetCacheUtils(Handler handler, LocalCacheUtils localCacheUtils, MemoryCacheUtils memoryCacheUtils) { 40 this.handler = handler; 41 service = Executors.newFixedThreadPool(10); 42 this.localCacheUtils = localCacheUtils; 43 this.memoryCacheUtils =memoryCacheUtils; 44 } 45 46 //聯(lián)網(wǎng)請(qǐng)求得到圖片 47 public void getBitmapFomNet(String imageUrl, int position) { 48 // new Thread(new MyRunnable(imageUrl,position)).start(); 49 service.execute(new MyRunnable(imageUrl,position)); 50 } 51 52 class MyRunnable implements Runnable{ 53 54 private final String imageUrl; 55 private final int position; 56 57 public MyRunnable(String imageUrl, int position) { 58 this.imageUrl = imageUrl; 59 this.position = position; 60 } 61 62 @Override 63 public void run() { 64 //子線程 65 //請(qǐng)求網(wǎng)絡(luò)圖片 66 try { 67 URL urL = new URL(imageUrl); 68 HttpURLConnection connection = (HttpURLConnection) urL.openConnection(); 69 connection.setRequestMethod("GET");//只能大寫(xiě) 70 connection.setConnectTimeout(4000); 71 connection.setReadTimeout(4000); 72 connection.connect();//可寫(xiě)可不寫(xiě) 73 int code = connection.getResponseCode(); 74 if(code ==200){ 75 InputStream is = connection.getInputStream(); 76 Bitmap bitmap = BitmapFactory.decodeStream(is); 77 78 //顯示到控件上,發(fā)消息吧Bitmap發(fā)出去和position 79 Message msg = Message.obtain(); 80 msg.what = SUCESS; 81 msg.arg1 = position; 82 msg.obj = bitmap; 83 handler.sendMessage(msg); 84 85 //在內(nèi)存中緩存一份 86 memoryCacheUtils.putBitmap(imageUrl,bitmap); 87 //在本地中緩存一份 88 localCacheUtils.putBitmap(imageUrl,bitmap); 89 } 90 } catch (IOException e) { 91 e.printStackTrace(); 92 Message msg = Message.obtain(); 93 msg.what = FAIL; 94 msg.arg1 = position; 95 handler.sendMessage(msg); 96 } 97 } 98 } 99 }
3.本地緩存
File file = new File(CACHE_DIR, fileName); FileInputStream FileOutputStream 文件讀寫(xiě)方式
演示把圖片移除后,在查看
C:\Users\Administrator>adb shell
# cd /mnt/sdcard/atguigu_beijingnews
cd /mnt/sdcard/atguigu_beijingnews
# rm *
rm *
1 package com.atguigu.beijingnews.utils; 2 3 import android.graphics.Bitmap; 4 import android.graphics.BitmapFactory; 5 import android.os.Environment; 6 7 import java.io.File; 8 import java.io.FileInputStream; 9 import java.io.FileOutputStream; 10 11 public class LocalCacheUtils { 12 private final MemoryCacheUtils memoryCacheUtils; 13 14 public LocalCacheUtils(MemoryCacheUtils memoryCacheUtils) { 15 this.memoryCacheUtils = memoryCacheUtils; 16 } 17 18 /** 19 * 根據(jù)Url獲取圖片 20 * @param imageUrl 21 * @return 22 */ 23 public Bitmap getBitmapFromUrl(String imageUrl) { 24 //判斷sdcard是否掛載 25 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ 26 //保存圖片在/mnt/sdcard/beijingnews/http://192.168.21.165:8080/xsxxxx.png 27 //保存圖片在/mnt/sdcard/beijingnews/llkskljskljklsjklsllsl 28 try { 29 String fileName = MD5Encoder.encode(imageUrl);//llkskljskljklsjklsllsl 30 31 ///mnt/sdcard/beijingnews/llkskljskljklsjklsllsl 32 File file = new File(Environment.getExternalStorageDirectory()+"/beijingnews",fileName); 33 34 35 36 37 if(file.exists()){ 38 39 FileInputStream is = new FileInputStream(file); 40 Bitmap bitmap = BitmapFactory.decodeStream(is); 41 if(bitmap != null){ 42 memoryCacheUtils.putBitmap(imageUrl,bitmap); 43 LogUtil.e("把從本地保持到內(nèi)存中"); 44 } 45 return bitmap; 46 47 } 48 49 } catch (Exception e) { 50 e.printStackTrace(); 51 LogUtil.e("圖片獲取失敗"); 52 } 53 } 54 55 return null; 56 } 57 58 /** 59 * 根據(jù)Url保存圖片 60 * @param imageUrl url 61 * @param bitmap 圖片 62 */ 63 public void putBitmap(String imageUrl, Bitmap bitmap) { 64 65 //判斷sdcard是否掛載 66 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ 67 //保存圖片在/mnt/sdcard/beijingnews/http://192.168.21.165:8080/xsxxxx.png 68 //保存圖片在/mnt/sdcard/beijingnews/llkskljskljklsjklsllsl 69 try { 70 String fileName = MD5Encoder.encode(imageUrl);//llkskljskljklsjklsllsl 71 72 ///mnt/sdcard/beijingnews/llkskljskljklsjklsllsl 73 File file = new File(Environment.getExternalStorageDirectory()+"/beijingnews",fileName); 74 75 File parentFile = file.getParentFile();//mnt/sdcard/beijingnews 76 if(!parentFile.exists()){ 77 //創(chuàng)建目錄 78 parentFile.mkdirs(); 79 } 80 81 82 if(!file.exists()){ 83 file.createNewFile(); 84 } 85 //保存圖片 86 bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file)); 87 88 } catch (Exception e) { 89 e.printStackTrace(); 90 LogUtil.e("圖片本地緩存失敗"); 91 } 92 } 93 94 95 } 96 }
4.內(nèi)存緩存
引用級(jí)別
我們經(jīng)常會(huì)使用一種非常流行的內(nèi)存緩存技術(shù)的實(shí)現(xiàn),即軟引用或弱引用 (SoftReference or WeakReference)。
但是現(xiàn)在已經(jīng)不再推薦使用這種方式了,因?yàn)閺?Android 2.3 (API Level 9)開(kāi)始,垃圾回收器會(huì)更傾向于回收持有軟引用或弱引用的對(duì)象;
另外,Android 3.0 (API Level 11)中,圖片的數(shù)據(jù)會(huì)存儲(chǔ)在本地的內(nèi)存當(dāng)中,因而無(wú)法用一種可預(yù)見(jiàn)的方式將其釋放,
這就有潛在的風(fēng)險(xiǎn)造成應(yīng)用程序的內(nèi)存溢出并崩潰。所以看到還有很多相關(guān)文章還在推薦用軟引用或弱引用 (SoftReference or WeakReference),就有點(diǎn)out了
Android3.0后提出新的方式
LruCache 緩存的集合,把常用的數(shù)據(jù),保留起來(lái),把不常用的給回收。
Lru近期最少使用算法
1 package com.atguigu.beijingnews.utils; 2 3 import android.graphics.Bitmap; 4 5 import org.xutils.cache.LruCache; 6 7 /** 8 * 作用:Java之軟引用&弱引用&虛引用 9 */ 10 public class MemoryCacheUtils { 11 12 /** 13 * 集合 14 */ 15 private LruCache<String,Bitmap> lruCache; 16 17 public MemoryCacheUtils(){ 18 //使用了系統(tǒng)分配給應(yīng)用程序的八分之一內(nèi)存來(lái)作為緩存大小 19 int maxSize = (int) (Runtime.getRuntime().maxMemory()/1024/8); 20 lruCache = new LruCache<String,Bitmap>(maxSize){ 21 @Override 22 protected int sizeOf(String key, Bitmap value) { 23 // return super.sizeOf(key, value); 24 return (value.getRowBytes() * value.getHeight())/1024; 25 } 26 }; 27 } 28 29 /** 30 * 根據(jù)url從內(nèi)存中獲取圖片 31 * @param imageUrl 32 * @return 33 */ 34 public Bitmap getBitmapFromUrl(String imageUrl) { 35 return lruCache.get(imageUrl); 36 } 37 38 /** 39 * 根據(jù)url保存圖片到lruCache集合中 40 * @param imageUrl 圖片路徑 41 * @param bitmap 圖片 42 */ 43 public void putBitmap(String imageUrl, Bitmap bitmap) { 44 lruCache.put(imageUrl,bitmap); 45 } 46 }
posted on 2016-10-31 00:35 安卓筆記俠 閱讀(350) 評(píng)論(0) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)