android非同步圖片載入三之handler+執行緒池+訊息佇列模式+快取
假象現在有這樣一個需求:
一個微部落格戶端或者多媒體客戶端需要從服務端拉取一些資料,該資料中包含了很多圖片,如果不用非同步載入方式,可能會使主執行緒阻塞導致ANR異常,但是非同步載入後如果每次都通過網路去下載圖片,效能上會差很多,而且也會浪費流量,導致使用者的不滿,故現在增加一個快取用來儲存圖片,快取中包含記憶體儲存和sdcard儲存。先從快取中去,在快取中先從記憶體中取出,如果記憶體中沒有再從sdcard去,如果sdcard中存在則直接返回該圖片資源並放入記憶體中,如果兩者都沒有則從網路上下載,下載後並放入sdcard中供下次使用,這樣就節約了資源開銷,下面是主要程式碼:
PicManager(用來處理圖片的操作):
- public class PicManager {
- private Map<String,SoftReference<Bitmap>> imgCache ;
- private Context ctx;
- public PicManager(Map<String,SoftReference<Bitmap>> imgCache,Context ctx) {
- this.ctx = ctx;
- this.imgCache = imgCache;
- }
- /**
- * 從網路上下載
- * @param url
- * @return
- */
- public Bitmap getBitMapFromUrl(String url) {
- Bitmap bitmap = null;
- URL u =null;
- HttpURLConnection conn = null;
- InputStream is = null;
- try {
- u = new URL(url);
- conn = (HttpURLConnection)u.openConnection();
- is = conn.getInputStream();
- bitmap = BitmapFactory.decodeStream(is);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return bitmap;
- }
- /**
- * 從檔案中讀取
- * @return
- * @throws Exception
- */
- private Bitmap getBitMapFromSDCard(String url) throws Exception {
- Bitmap bitmap = null;
- String filename = MD5Util.getMD5(url);
- FileInputStream fis = ctx.openFileInput(filename);
- bitmap = BitmapFactory.decodeStream(fis);
- return bitmap;
- }
- /**
- * 從快取中讀取
- * @param url
- * @return
- * @throws Exception
- */
- public Bitmap getImgFromCache(String url) throws Exception {
- Bitmap bitmap = null;
- //從記憶體中讀取
- if(imgCache.containsKey(url)) {
- synchronized (imgCache) {
- SoftReference<Bitmap> bitmapReference = imgCache.get(url);
- if(null != bitmapReference) {
- bitmap = bitmapReference.get();
- }
- }
- } else {//否則從檔案中讀取
- bitmap = getBitMapFromSDCard(url);
- //將圖片儲存進記憶體中
- imgCache.put(url, new SoftReference<Bitmap>(bitmap));
- }
- return bitmap;
- }
- /**
- * 將圖片寫入sdcard中
- * @param bitmap
- * @param url
- * @throws Exception
- */
- public void writePic2SDCard(Bitmap bitmap,String url) throws Exception {
- String filename = MD5Util.getMD5(url);
- FileOutputStream fos = ctx.openFileOutput(filename, ctx.MODE_APPEND);
- byte[] bitmapByte = PictureUtil.bitmap2Byte(bitmap);
- ByteArrayInputStream bis = new ByteArrayInputStream(bitmapByte);
- int len = 0;
- byte[] b = new byte[bis.available()];
- while((len = bis.read(b)) != -1) {
- fos.write(b, 0, len);
- }
- if(null != bis) {
- bis.close();
- }
- if(null != fos) {
- fos.close();
- }
- }
- }
ImgLoader(用來加在圖片):
- public class ImgLoader {
- private Map<String,SoftReference<Bitmap>> imgCache = new HashMap<String,SoftReference<Bitmap>>();
- private Context ctx;
- public ImgLoader(Context ctx) {
- this.ctx = ctx;
- }
- private PicManager manager = new PicManager(imgCache,ctx);
- private Handler handler = new Handler();
- private ExecutorService threadPool = Executors.newFixedThreadPool(5);
- public Bitmap loadImg(final String url,final ImgCallback callback) {
- //先從快取中讀取圖片資源
- Bitmap bitmap = null;
- try {
- bitmap = manager.getImgFromCache(url);;
- if(null == bitmap) {
- //開啟執行緒從網路上下載
- threadPool.submit(new Runnable() {//submit方法確保下載是從執行緒池中的執行緒執行
- @Override
- public void run() {
- final Bitmap bitmapFromUrl = manager.getBitMapFromUrl(url);
- try {
- manager.writePic2SDCard(bitmapFromUrl,url);
- } catch (Exception e) {
- e.printStackTrace();
- }
- handler.post(new Runnable() {
- @Override
- public void run() {
- callback.refresh(bitmapFromUrl);
- }
- });
- }
- });
- } else {
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return bitmap;
- }
- }
ImgCallback callback是一個介面,用來重新整理介面
- public interface ImgCallback {
- public void refresh(Bitmap bitmap);
- }
相關文章
- python 的執行緒池如何獲取 work 佇列中的訊息數量Python執行緒佇列
- android ListView非同步載入圖片(雙快取)AndroidView非同步快取
- Swift多執行緒之Operation:非同步載入CollectionView圖片Swift執行緒非同步View
- 【構建Android快取模組】(三)Controller & 非同步圖片載入Android快取Controller非同步
- C++ 多執行緒框架(3):訊息佇列C++執行緒框架佇列
- 剖析 Redis List 訊息佇列的三種消費執行緒模型Redis佇列執行緒模型
- java多執行緒:執行緒池原理、阻塞佇列Java執行緒佇列
- java執行緒池-工作佇列workQueueJava執行緒佇列
- 執行緒池與工作佇列(轉)執行緒佇列
- iOS 多執行緒--GCD 序列佇列、併發佇列以及同步執行、非同步執行iOS執行緒GC佇列非同步
- Python中執行緒的MQ訊息佇列實現以及訊息佇列的優點解析Python執行緒MQ佇列
- 訊息佇列之-RocketMQ入門佇列MQ
- iOS執行緒、同步非同步、序列並行佇列iOS執行緒非同步並行佇列
- 執行緒池的阻塞佇列的理解執行緒佇列
- python多執行緒中訊息佇列如何實現?Python執行緒佇列
- Android多執行緒之執行緒池Android執行緒
- Android 視訊縮圖的快取機制和非同步載入Android快取非同步
- RabbitMQ 訊息佇列之佇列模型MQ佇列模型
- Android執行緒管理之ExecutorService執行緒池Android執行緒
- java-執行緒池佇列飽和策略Java執行緒佇列
- Java同步之執行緒池詳解Java執行緒
- 訊息佇列之RabbitMQ佇列MQ
- 訊息佇列之RocketMQ佇列MQ
- 訊息佇列之 RabbitMQ佇列MQ
- 訊息佇列之 Kafka佇列Kafka
- 訊息佇列之 ActiveMQ佇列MQ
- 訊息佇列之 RocketMQ佇列MQ
- 執行緒(十八)J.U.C之AQS:CLH同步佇列執行緒AQS佇列
- 多執行緒,執行緒類三種方式,執行緒排程,執行緒同步,死鎖,執行緒間的通訊,阻塞佇列,wait和sleep區別?執行緒佇列AI
- 除了訊息佇列,以下這些高階技術也可用於獲取執行緒執行結果佇列執行緒
- 多執行緒之間通訊及執行緒池執行緒
- android 主執行緒和子執行緒之間的訊息傳遞Android執行緒
- 探討阻塞佇列和執行緒池原始碼佇列執行緒原始碼
- Java幾種執行緒池及任務佇列Java執行緒佇列
- Android 執行緒優化之執行緒池shutdown方法Android執行緒優化
- 訊息佇列之概論佇列
- Redis 應用-非同步訊息佇列與延時佇列Redis非同步佇列
- Swift多執行緒之Operation:按優先順序載入圖片Swift執行緒