国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android實現圖片緩存與異步加載

2020-04-11 10:47:45
字體:
來源:轉載
供稿:網友

ImageManager2這個類具有異步從網絡下載圖片,從sd讀取本地圖片,內存緩存,硬盤緩存,圖片使用動畫漸現等功能,已經將其應用在包含大量圖片的應用中一年多,沒有出現oom。

Android程序常常會內存溢出,網上也有很多解決方案,如軟引用,手動調用recycle等等。但經過我們實踐發現這些方案,都沒能起到很好的效果,我們的應用依然會出現很多oom,尤其我們的應用包含大量的圖片。android3.0之后軟引用基本已經失效,因為虛擬機只要碰到軟引用就回收,所以帶不來任何性能的提升。

我這里的解決方案是HandlerThread(異步加載)+LruCache(內存緩存)+DiskLruCache(硬盤緩存)。

作為程序員,我也不多說,直接和大家共享我的代碼,用代碼交流更方便些。

package com.example.util; import java.io.File;import java.util.Iterator;import java.util.LinkedList;import java.util.Queue;import java.util.Stack; import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.util.EntityUtils; import android.app.ActivityManager;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.ColorDrawable;import android.graphics.drawable.Drawable;import android.graphics.drawable.TransitionDrawable;import android.media.ThumbnailUtils;import android.os.Handler;import android.os.HandlerThread;import android.os.Looper;import android.os.Message;import android.support.v4.util.LruCache;import android.widget.ImageView; import com.example.MyApplication; /** * 圖片加載類 *  * @author 月月鳥 */public class ImageManager2 {   private static ImageManager2 imageManager;  public LruCache<String, Bitmap> mMemoryCache;  private static final int DISK_CACHE_SIZE = 1024 * 1024 * 20; // 10MB  private static final String DISK_CACHE_SUBDIR = "thumbnails";  public DiskLruCache mDiskCache;  private static MyApplication myapp;   /** 圖片加載隊列,后進先出 */  private Stack<ImageRef> mImageQueue = new Stack<ImageRef>();   /** 圖片請求隊列,先進先出,用于存放已發送的請求。 */  private Queue<ImageRef> mRequestQueue = new LinkedList<ImageRef>();   /** 圖片加載線程消息處理器 */  private Handler mImageLoaderHandler;   /** 圖片加載線程是否就緒 */  private boolean mImageLoaderIdle = true;   /** 請求圖片 */  private static final int MSG_REQUEST = 1;  /** 圖片加載完成 */  private static final int MSG_REPLY = 2;  /** 中止圖片加載線程 */  private static final int MSG_STOP = 3;  /** 如果圖片是從網絡加載,則應用漸顯動畫,如果從緩存讀出則不應用動畫 */  private boolean isFromNet = true;   /**   * 獲取單例,只能在UI線程中使用。   *    * @param context   * @return   */  public static ImageManager2 from(Context context) {     // 如果不在ui線程中,則拋出異常    if (Looper.myLooper() != Looper.getMainLooper()) {      throw new RuntimeException("Cannot instantiate outside UI thread.");    }     if (myapp == null) {      myapp = (MyApplication) context.getApplicationContext();    }     if (imageManager == null) {      imageManager = new ImageManager2(myapp);    }     return imageManager;  }   /**   * 私有構造函數,保證單例模式   *    * @param context   */  private ImageManager2(Context context) {    int memClass = ((ActivityManager) context        .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();    memClass = memClass > 32 ? 32 : memClass;    // 使用可用內存的1/8作為圖片緩存    final int cacheSize = 1024 * 1024 * memClass / 8;     mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {       protected int sizeOf(String key, Bitmap bitmap) {        return bitmap.getRowBytes() * bitmap.getHeight();      }     };     File cacheDir = DiskLruCache        .getDiskCacheDir(context, DISK_CACHE_SUBDIR);    mDiskCache = DiskLruCache.openCache(context, cacheDir, DISK_CACHE_SIZE);   }   /**   * 存放圖片信息   */  class ImageRef {     /** 圖片對應ImageView控件 */    ImageView imageView;    /** 圖片URL地址 */    String url;    /** 圖片緩存路徑 */    String filePath;    /** 默認圖資源ID */    int resId;    int width = 0;    int height = 0;     /**     * 構造函數     *      * @param imageView     * @param url     * @param resId     * @param filePath     */    ImageRef(ImageView imageView, String url, String filePath, int resId) {      this.imageView = imageView;      this.url = url;      this.filePath = filePath;      this.resId = resId;    }     ImageRef(ImageView imageView, String url, String filePath, int resId,        int width, int height) {      this.imageView = imageView;      this.url = url;      this.filePath = filePath;      this.resId = resId;      this.width = width;      this.height = height;    }   }   /**   * 顯示圖片   *    * @param imageView   * @param url   * @param resId   */  public void displayImage(ImageView imageView, String url, int resId) {    if (imageView == null) {      return;    }    if (imageView.getTag() != null        && imageView.getTag().toString().equals(url)) {      return;    }    if (resId >= 0) {      if (imageView.getBackground() == null) {        imageView.setBackgroundResource(resId);      }      imageView.setImageDrawable(null);     }    if (url == null || url.equals("")) {      return;    }     // 添加url tag    imageView.setTag(url);     // 讀取map緩存    Bitmap bitmap = mMemoryCache.get(url);    if (bitmap != null) {      setImageBitmap(imageView, bitmap, false);      return;    }     // 生成文件名    String filePath = urlToFilePath(url);    if (filePath == null) {      return;    }     queueImage(new ImageRef(imageView, url, filePath, resId));  }   /**   * 顯示圖片固定大小圖片的縮略圖,一般用于顯示列表的圖片,可以大大減小內存使用   *    * @param imageView 加載圖片的控件   * @param url 加載地址   * @param resId 默認圖片   * @param width 指定寬度   * @param height 指定高度   */  public void displayImage(ImageView imageView, String url, int resId,      int width, int height) {    if (imageView == null) {      return;    }    if (resId >= 0) {       if (imageView.getBackground() == null) {        imageView.setBackgroundResource(resId);      }      imageView.setImageDrawable(null);     }    if (url == null || url.equals("")) {      return;    }     // 添加url tag    imageView.setTag(url);    // 讀取map緩存    Bitmap bitmap = mMemoryCache.get(url + width + height);    if (bitmap != null) {      setImageBitmap(imageView, bitmap, false);      return;    }     // 生成文件名    String filePath = urlToFilePath(url);    if (filePath == null) {      return;    }     queueImage(new ImageRef(imageView, url, filePath, resId, width, height));  }   /**   * 入隊,后進先出   *    * @param imageRef   */  public void queueImage(ImageRef imageRef) {     // 刪除已有ImageView    Iterator<ImageRef> iterator = mImageQueue.iterator();    while (iterator.hasNext()) {      if (iterator.next().imageView == imageRef.imageView) {        iterator.remove();      }    }     // 添加請求    mImageQueue.push(imageRef);    sendRequest();  }   /**   * 發送請求   */  private void sendRequest() {     // 開啟圖片加載線程    if (mImageLoaderHandler == null) {      HandlerThread imageLoader = new HandlerThread("image_loader");      imageLoader.start();      mImageLoaderHandler = new ImageLoaderHandler(          imageLoader.getLooper());    }     // 發送請求    if (mImageLoaderIdle && mImageQueue.size() > 0) {      ImageRef imageRef = mImageQueue.pop();      Message message = mImageLoaderHandler.obtainMessage(MSG_REQUEST,          imageRef);      mImageLoaderHandler.sendMessage(message);      mImageLoaderIdle = false;      mRequestQueue.add(imageRef);    }  }   /**   * 圖片加載線程   */  class ImageLoaderHandler extends Handler {     public ImageLoaderHandler(Looper looper) {      super(looper);    }     public void handleMessage(Message msg) {      if (msg == null)        return;       switch (msg.what) {       case MSG_REQUEST: // 收到請求        Bitmap bitmap = null;        Bitmap tBitmap = null;        if (msg.obj != null && msg.obj instanceof ImageRef) {           ImageRef imageRef = (ImageRef) msg.obj;          String url = imageRef.url;          if (url == null)            return;          // 如果本地url即讀取sd相冊圖片,則直接讀取,不用經過DiskCache          if (url.toLowerCase().contains("dcim")) {             tBitmap = null;            BitmapFactory.Options opt = new BitmapFactory.Options();            opt.inSampleSize = 1;            opt.inJustDecodeBounds = true;            BitmapFactory.decodeFile(url, opt);            int bitmapSize = opt.outHeight * opt.outWidth * 4;            opt.inSampleSize = bitmapSize / (1000 * 2000);            opt.inJustDecodeBounds = false;            tBitmap = BitmapFactory.decodeFile(url, opt);            if (imageRef.width != 0 && imageRef.height != 0) {              bitmap = ThumbnailUtils.extractThumbnail(tBitmap,                  imageRef.width, imageRef.height,                  ThumbnailUtils.OPTIONS_RECYCLE_INPUT);              isFromNet = true;            } else {              bitmap = tBitmap;              tBitmap = null;            }           } else            bitmap = mDiskCache.get(url);           if (bitmap != null) {            // ToolUtil.log("從disk緩存讀取");            // 寫入map緩存            if (imageRef.width != 0 && imageRef.height != 0) {              if (mMemoryCache.get(url + imageRef.width                  + imageRef.height) == null)                mMemoryCache.put(url + imageRef.width                    + imageRef.height, bitmap);            } else {              if (mMemoryCache.get(url) == null)                mMemoryCache.put(url, bitmap);            }           } else {            try {              byte[] data = loadByteArrayFromNetwork(url);               if (data != null) {                 BitmapFactory.Options opt = new BitmapFactory.Options();                opt.inSampleSize = 1;                 opt.inJustDecodeBounds = true;                BitmapFactory.decodeByteArray(data, 0,                    data.length, opt);                int bitmapSize = opt.outHeight * opt.outWidth                    * 4;// pixels*3 if it's RGB and pixels*4                      // if it's ARGB                if (bitmapSize > 1000 * 1200)                  opt.inSampleSize = 2;                opt.inJustDecodeBounds = false;                tBitmap = BitmapFactory.decodeByteArray(data,                    0, data.length, opt);                if (imageRef.width != 0 && imageRef.height != 0) {                  bitmap = ThumbnailUtils                      .extractThumbnail(                          tBitmap,                          imageRef.width,                          imageRef.height,                          ThumbnailUtils.OPTIONS_RECYCLE_INPUT);                } else {                  bitmap = tBitmap;                  tBitmap = null;                }                 if (bitmap != null && url != null) {                  // 寫入SD卡                  if (imageRef.width != 0                      && imageRef.height != 0) {                    mDiskCache.put(url + imageRef.width                        + imageRef.height, bitmap);                    mMemoryCache.put(url + imageRef.width                        + imageRef.height, bitmap);                  } else {                    mDiskCache.put(url, bitmap);                    mMemoryCache.put(url, bitmap);                  }                  isFromNet = true;                }              }            } catch (OutOfMemoryError e) {            }           }         }         if (mImageManagerHandler != null) {          Message message = mImageManagerHandler.obtainMessage(              MSG_REPLY, bitmap);          mImageManagerHandler.sendMessage(message);        }        break;       case MSG_STOP: // 收到終止指令        Looper.myLooper().quit();        break;       }    }  }   /** UI線程消息處理器 */  private Handler mImageManagerHandler = new Handler() {     @Override    public void handleMessage(Message msg) {      if (msg != null) {        switch (msg.what) {         case MSG_REPLY: // 收到應答           do {            ImageRef imageRef = mRequestQueue.remove();             if (imageRef == null)              break;             if (imageRef.imageView == null                || imageRef.imageView.getTag() == null                || imageRef.url == null)              break;             if (!(msg.obj instanceof Bitmap) || msg.obj == null) {              break;            }            Bitmap bitmap = (Bitmap) msg.obj;             // 非同一ImageView            if (!(imageRef.url).equals((String) imageRef.imageView                .getTag())) {              break;            }             setImageBitmap(imageRef.imageView, bitmap, isFromNet);            isFromNet = false;           } while (false);           break;        }      }      // 設置閑置標志      mImageLoaderIdle = true;       // 若服務未關閉,則發送下一個請求。      if (mImageLoaderHandler != null) {        sendRequest();      }    }  };   /**   * 添加圖片顯示漸現動畫   *    */  private void setImageBitmap(ImageView imageView, Bitmap bitmap,      boolean isTran) {    if (isTran) {      final TransitionDrawable td = new TransitionDrawable(          new Drawable[] {              new ColorDrawable(android.R.color.transparent),              new BitmapDrawable(bitmap) });      td.setCrossFadeEnabled(true);      imageView.setImageDrawable(td);      td.startTransition(300);    } else {      imageView.setImageBitmap(bitmap);    }  }   /**   * 從網絡獲取圖片字節數組   *    * @param url   * @return   */  private byte[] loadByteArrayFromNetwork(String url) {     try {       HttpGet method = new HttpGet(url);      HttpResponse response = myapp.getHttpClient().execute(method);      HttpEntity entity = response.getEntity();      return EntityUtils.toByteArray(entity);     } catch (Exception e) {      return null;    }   }   /**   * 根據url生成緩存文件完整路徑名   *    * @param url   * @return   */  public String urlToFilePath(String url) {     // 擴展名位置    int index = url.lastIndexOf('.');    if (index == -1) {      return null;    }     StringBuilder filePath = new StringBuilder();     // 圖片存取路徑    filePath.append(myapp.getCacheDir().toString()).append('/');     // 圖片文件名     filePath.append(MD5.Md5(url)).append(url.substring(index));     return filePath.toString();  }   /**   * Activity#onStop后,ListView不會有殘余請求。   */  public void stop() {     // 清空請求隊列    mImageQueue.clear();   } }

這里就是給出了異步加載、內存緩存和硬盤緩存的解決方案,希望對大家的學習有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 广东省| 麻阳| 达孜县| 铜川市| 巩留县| 泰顺县| 南郑县| 潮州市| 城市| 革吉县| 邹城市| 依安县| 怀化市| 苍溪县| 乐平市| 金溪县| 三穗县| 申扎县| 闸北区| 城固县| 土默特右旗| 杂多县| 九龙坡区| 寿阳县| 沈丘县| 怀来县| 肥城市| 东宁县| 灵川县| 临漳县| 阿拉善右旗| 澄迈县| 枝江市| 屏南县| 九台市| 水城县| 承德县| 磐安县| 韶关市| 胶南市| 康平县|