Android Open Source - Android-Fast-ImageLoader Cache Worker






From Project

Back to project page Android-Fast-ImageLoader.

License

The source code is released under:

Apache License

If you think the Android project Android-Fast-ImageLoader listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.sunny.cache;
//from w  ww. j a  v a2 s  .  c  o m
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.text.TextUtils;
import android.widget.ImageView;

import com.sunny.net.DHttpClient;
import com.sunny.threadpool.DThreadPool;
import com.sunny.threadpool.IDThreadPool;
import com.sunny.threadpool.IPriorityTask;
import com.sunny.threadpool.TaskPriority;
import com.sunny.util.ImageUtil;
import com.sunny.util.MD5Util;
import com.sunny.util.Utils;

/**
 * Base Cache tools
 * 
 * @author Kang, Leo
 */
public class CacheWorker {

  // Schedule of report download progress
  private static final long SCHEDULE_REPORT = 300l;

  // Max of cache size in SD-Card
  private final long MAX_CACHE_SIZE = 500 * 1024 * 1024;

  // Min of cache size in SD-Card
  private final static long MIN_CACHE_SIZE = 5 * 1024 * 1024;

  // Flag for enable auto clean Cache.
  public boolean cleanCache = true;

  // Default clean cached files in SD-Card.
  private static final float PERCENT_CLEAN = 0.4f;

  // Custom suffix.Mark the file is GIF.
  public static final String GIF_END = ".gif";

  protected Context mContext;

  // Flag for network
  volatile static boolean networkEnable = true;

  // Flag for SD-Card
  volatile static boolean sdcardCache = true;

  protected String tag = "";

  // If table is shown.
  protected boolean onScreen = true;

  // Thread Pool to handle task. Tasks used to search local files.
  protected IDThreadPool searchThreadPool;

  // Thread Pool to handle task. Tasks used to downlaod file.
  protected IDThreadPool downloadThreadQueue;

  private final MemoryCache mCache;

  // Base path
  protected String storePath;

  private boolean timeSortASC = true;

  protected Resources mResources;

  private final Object restartLock = new Object();

  private int downloadPoolMaxCore = 1;

  public CacheWorker(Context context, String cachePath, boolean timeSortASC) {
    this.mContext = context;
    mResources = context.getResources();
    this.timeSortASC = timeSortASC;
    downloadPoolMaxCore = Runtime.getRuntime().availableProcessors();
    final int cacheSize = (int) (Runtime.getRuntime().maxMemory() / 8);
    // (int) (Runtime.getRuntime().maxMemory() >> 12);
    mCache = new MemoryCache(cacheSize);
    searchThreadPool = DThreadPool.newThreadPool(downloadPoolMaxCore, 20,
        5, !timeSortASC);
    downloadThreadQueue = DThreadPool.newThreadPool(downloadPoolMaxCore, 6,
        2, !timeSortASC);

    final ConnectivityManager cwjManager = (ConnectivityManager) context
        .getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo info = cwjManager.getActiveNetworkInfo();
    if (info == null) {
      networkEnable = false;
    } else {
      networkEnable = info.isAvailable();
    }
    storePath = cachePath;

    // String status = Environment.getExternalStorageState();
    // if (status.equals(Environment.MEDIA_MOUNTED)) {
    // long allFileSize = 0;
    // File storeFile = Environment.getExternalStorageDirectory();
    // // String basePath = storeFile.getPath();
    // File destDir = new File(cachePath);
    // storePath = destDir.getPath();
    // if (!destDir.exists()) {
    // destDir.mkdirs();
    // } else {
    // File[] conFiles = destDir.listFiles();
    // for (File cf : conFiles) {
    // allFileSize += cf.length();
    // }
    // }
    // long sdFree = (getUsableSpace(storeFile)) - allFileSize;
    // if (sdFree < MIN_CACHE_SIZE) {
    // sdcardCache = false;
    // }
    // } else {
    // sdcardCache = false;
    // }
  }

  private static boolean checkFileCache(String cachePath) {
    boolean result = false;
    if (!TextUtils.isEmpty(cachePath)) {
      long allFileSize = 0;
      File storeFile = Environment.getExternalStorageDirectory();
      File destDir = new File(cachePath);
      if (destDir.exists()) {
        File[] conFiles = destDir.listFiles();
        for (File cf : conFiles) {
          allFileSize += cf.length();
        }
        long sdFree = (getUsableSpace(storeFile)) - allFileSize;
        result = (sdFree >= MIN_CACHE_SIZE);
      }
    } else {
      result = false;
    }
    return result;
  }

  protected synchronized void doLoadRemoteImage(String url, ImageView view,
      Builder cacheParams, OnSetImageListener setImageListener) {
    synchronized (view) {
      // viewPool.add(new WeakReference<ImageView>(view));

      BitmapDrawable value = mCache.exist(packKey(url, cacheParams));
      if (value != null) {
        // view.setImageDrawable(value);
        setImageListener.onFinish(view, value, cacheParams, true);

      } else if (cancelWork(false, url, view)) {

        final SearchTask task = new SearchTask(getTag(), url, view,
            cacheParams, false, setImageListener);
        Drawable ad = null;
        if (cacheParams.loadingImage > 0) {
          Drawable d = mResources
              .getDrawable(cacheParams.loadingImage);
          if (d != null) {
            if (d instanceof BitmapDrawable) {
              Bitmap loadingBitmap = ((BitmapDrawable) d)
                  .getBitmap();
              ad = (loadingBitmap == null ? new AsyncDrawable(
                  mContext.getResources(), task)
                  : new AsyncDrawable(
                      mContext.getResources(),
                      loadingBitmap, task));
            }
          }
        }
        if (ad == null) {
          ad = new AsyncDrawable(mContext.getResources(), task);
        }
        view.setImageDrawable(ad);
        searchThreadPool.put(tag, task, TaskPriority.UI_NORM);
      }
    }
  }

  protected synchronized void doLoadLocalImage(String filename,
      ImageView view, Builder cacheParams, Bitmap loadingBitmap,
      OnSetImageListener setImageListener) {
    synchronized (view) {
      // viewPool.add(new WeakReference<ImageView>(view));
      BitmapDrawable value = mCache.exist(packKey(filename, cacheParams));
      if (value != null) {
        view.setImageDrawable(value);
      } else if (cancelWork(false, view, filename)) {
        final SearchTask task = new SearchTask(getTag(), view,
            cacheParams, filename, false, setImageListener);
        final AsyncDrawable ad = (loadingBitmap == null ? new AsyncDrawable(
            mContext.getResources(), task) : new AsyncDrawable(
            mContext.getResources(), loadingBitmap, task));
        view.setImageDrawable(ad);
        searchThreadPool.put(tag, task, TaskPriority.UI_NORM);
      }
    }
  }

  class SearchTask implements IPriorityTask {
    private final WeakReference<ImageView> imageViewReference;
    private String url;
    private final Builder mCacheParams;
    private boolean stop;
    // public boolean isBig = false;

    private String filename = "";
    private IDownloadHandler listener = null;
    private final String screenName;
    private boolean isBackground = false;
    private final OnSetImageListener setImageListener;
    private boolean isGIF = false;
    private final boolean isCancled = false;

    // private boolean handleGIF = false;

    public SearchTask(String scrrenName, ImageView view,
        Builder cacheParams, boolean isBackground,
        OnSetImageListener setImageListener) {
      this.setImageListener = setImageListener;
      imageViewReference = new WeakReference<ImageView>(view);
      this.screenName = scrrenName;
      this.mCacheParams = cacheParams;
      this.isBackground = isBackground;
      // this.handleGIF = cacheParams.supportGIF;
    }

    /**
     * Used for remote image searching in local files.
     */
    public SearchTask(String scrrenName, String url, ImageView view,
        Builder cacheParams, boolean isBackground,
        OnSetImageListener setImageListener) {
      this(scrrenName, view, cacheParams, isBackground, setImageListener);
      this.url = url;
      isGIF = (url.endsWith(".gif")) || (url.endsWith(".GIF"));
    }

    public SearchTask(String scrrenName, ImageView view,
        Builder cacheParams, String filename, boolean isBackground,
        OnSetImageListener setImageListener) {
      this(scrrenName, view, cacheParams, isBackground, setImageListener);
      this.filename = filename;
      isGIF = judgeGIF(filename);
    }

    public synchronized void cancelWork() {
      stop = true;
      listener = null;
    }

    @Override
    public void run() {
      if (TextUtils.isEmpty(filename)) {
        loadRemote();
      } else {
        loadLocal();
      }
    }

    private void loadLocal() {
      Bitmap bitmap = null;
      if ((!stop) && (getAttachedImageView() != null) && sdcardCache
          && onScreen) {
        // exist in SDcard
        final File file = new File(filename);
        if (isGIF && file.exists() && (!mCacheParams.supportGIF)
            && setImageListener != null) {
          setImageListener.onLoadGIF(filename);
          // gifListener.onFinish(filename);
          return;
        }
        bitmap = isGIF ? readFromGIFFile(file) : readFromFile(file);
        if (bitmap != null) {
          final ImageView imageView = getAttachedImageView();
          if (imageView != null && (!stop) && onScreen) {
            BitmapDrawable drawable = null;
            if (Utils.hasHoneycomb()) {
              // Running on Honeycomb or newer, so wrap in a
              // standard BitmapDrawable
              drawable = new BitmapDrawable(mResources, bitmap);
            } else {
              // Running on Gingerbread or older, so wrap in a
              // RecyclingBitmapDrawable
              // which will recycle automagically
              drawable = new RecyclingBitmapDrawable(mResources,
                  bitmap);
            }
            mCache.put(packKey(filename, mCacheParams), drawable);
            if (setImageListener != null) {
              setImageListener.onFinish(imageView, drawable,
                  mCacheParams, true);
            }
          } else {
            bitmap.recycle();
          }
        } else {
          // set error image
          final ImageView imageView = getAttachedImageView();
          if (imageView != null && (!stop) && onScreen) {
            if (setImageListener != null) {
              setImageListener.onError();
            }
          }
        }
      }
    }

    private void loadRemote() {
      Bitmap bitmap = null;
      final String filename = getFileName(url);
      if ((!stop) && (getAttachedImageView() != null) && sdcardCache
          && onScreen) {
        // exist in SDcard
        final File file = new File(storePath, filename);
        if ((!mCacheParams.supportGIF) && isGIF && file.exists()
            && setImageListener != null) {
          setImageListener.onLoadGIF(file.getAbsolutePath());
          return;
        }
        bitmap = isGIF ? readFromGIFFile(file) : readFromFile(file);
      }
      if (bitmap == null) {
        // Add download task.
        listener = new IDownloadHandler() {
          long lastUpdate = System.currentTimeMillis();

          @Override
          public void onFinish() {
            if ((!stop) && (getAttachedImageView() != null)
                && onScreen) {
              final File file = new File(storePath, filename);
              if ((!mCacheParams.supportGIF) && isGIF
                  && file.exists()
                  && (setImageListener != null)) {
                setImageListener.onLoadGIF(file
                    .getAbsolutePath());
                return;
              }
              Bitmap bitmap = readFromFile(file);
              final ImageView imageView = getAttachedImageView();
              if (imageView != null && (!stop) && bitmap != null
                  && onScreen) {
                BitmapDrawable drawable = null;
                if (Utils.hasHoneycomb()) {
                  // Running on Honeycomb or newer, so wrap in
                  // a
                  // standard BitmapDrawable
                  drawable = new BitmapDrawable(mResources,
                      bitmap);
                } else {
                  // Running on Gingerbread or older, so wrap
                  // in a
                  // RecyclingBitmapDrawable
                  // which will recycle automagically
                  drawable = new RecyclingBitmapDrawable(
                      mResources, bitmap);
                }
                mCache.put(packKey(url, mCacheParams), drawable);
                if (setImageListener != null) {
                  setImageListener.onFinish(imageView,
                      drawable, mCacheParams, false);
                }
              } else {
                if (bitmap != null) {
                  bitmap.recycle();
                }
              }
            }
          }

          @Override
          public void onError() {
            final ImageView imageView = getAttachedImageView();
            if (imageView != null && (!stop) && onScreen
                && (setImageListener != null)) {
              setImageListener.onError();
            }
          }

          @Override
          public void onStart() {
            final ImageView imageView = getAttachedImageView();
            if (imageView != null && (!stop) && onScreen
                && (setImageListener != null)) {
              setImageListener.onStartDownloading();
            }
          }

          @Override
          public void onProgress(int i) {
            final long now = System.currentTimeMillis();
            if ((now - lastUpdate) > SCHEDULE_REPORT) {
              lastUpdate = now;
              final ImageView imageView = getAttachedImageView();
              if (imageView != null && (!stop) && onScreen
                  && (setImageListener != null)) {
                setImageListener.onProgress(i);
              }
            }

          }

          @Override
          public void onFinishNoFile(Bitmap bitmap) {

            if ((!stop) && (getAttachedImageView() != null)
                && onScreen) {
              // Rough practice
              final ImageView imageView = getAttachedImageView();
              if (imageView != null && (!stop) && bitmap != null
                  && onScreen) {
                BitmapDrawable drawable = null;
                if (Utils.hasHoneycomb()) {
                  // Running on Honeycomb or newer, so wrap in
                  // a
                  // standard BitmapDrawable
                  drawable = new BitmapDrawable(mResources,
                      bitmap);
                } else {
                  // Running on Gingerbread or older, so wrap
                  // in a
                  // RecyclingBitmapDrawable
                  // which will recycle automagically
                  drawable = new RecyclingBitmapDrawable(
                      mResources, bitmap);
                }
                mCache.put(packKey(url, mCacheParams), drawable);
                if (setImageListener != null) {
                  setImageListener.onFinish(imageView,
                      drawable, mCacheParams, false);
                }
              } else {
                if (bitmap != null) {
                  bitmap.recycle();
                }
              }
            }

          }
        };
        if (setImageListener != null) {
          setImageListener.onStart(getAttachedImageView(), url);
        }
        DownloadTask task = new DownloadTask(url, filename, listener);
        downloadThreadQueue.put(screenName, task, TaskPriority.UI_NORM);
        return;
      } else {
        final ImageView imageView = getAttachedImageView();
        if (imageView != null && (!stop) && onScreen) {
          BitmapDrawable drawable = null;
          if (Utils.hasHoneycomb()) {
            // Running on Honeycomb or newer, so wrap in
            // a
            // standard BitmapDrawable
            drawable = new BitmapDrawable(mResources, bitmap);
          } else {
            // Running on Gingerbread or older, so wrap
            // in a
            // RecyclingBitmapDrawable
            // which will recycle automagically
            drawable = new RecyclingBitmapDrawable(mResources,
                bitmap);
          }
          mCache.put(packKey(url, mCacheParams), drawable);
          if (setImageListener != null) {

            setImageListener.onFinish(imageView, drawable,
                mCacheParams, true);
          }
          // setImageBitmap(imageView, bitmap);
        } else {
          bitmap.recycle();
        }
      }
    }

    private Bitmap readFromFile(File file) {
      Bitmap bitmap = null;
      if (file.exists()) {
        bitmap = decodeBitmap(file.getAbsolutePath(),
            mCacheParams.imageWidth, mCacheParams.imageHeight,
            mCacheParams.isScale);
        if (mCacheParams.needRotation && bitmap != null
            && bitmap.getWidth() > bitmap.getHeight()) {
          bitmap = ImageUtil.adjustPhotoRotation(bitmap, 91);
          return bitmap;
        }
        // add support for grey image.
        if (mCacheParams.greyImage && (bitmap != null)) {
          bitmap = ImageUtil.toGrayscale(bitmap);
        }
        if (mCacheParams.needRounded && (bitmap != null)) {
          Bitmap nb = cutCircularImage(bitmap);
          return nb;
        }
        if ((mCacheParams.spRounded > 0) && (bitmap != null)) {
          // Bitmap nb = cutRoundedImage(mCacheParams.spRounded,
          // bitmap);
          Bitmap nb = getRoundedImage(mCacheParams.spRounded, bitmap);
          return nb;
        }
      }
      return bitmap;
    }

    private Bitmap readFromGIFFile(File file) {
      Bitmap bitmap = null;
      if (file.exists()) {
        try {
          GIFDecoder decoder = new GIFDecoder();
          bitmap = decoder.read(new FileInputStream(file));
          decoder = null;
        } catch (Exception e) {
        }
      }
      return bitmap;
    }

    /**
     * Returns the ImageView associated with this task as long as the
     * ImageView's task still points to this task as well. Returns null
     * otherwise.
     */
    private ImageView getAttachedImageView() {
      final ImageView imageView = imageViewReference.get();
      final SearchTask bitmapWorkerTask = getSearchTask(isBackground,
          imageView);

      if (this == bitmapWorkerTask) {
        return imageView;
      }

      return null;
    }

    @Override
    public String getFlag() {
      return url;
    }

    @Override
    public boolean onRepeatPut(IPriorityTask newTask) {
      return false;
    }

    @Override
    public void isolateFlag() {

    }

    @Override
    public boolean unregisterListener(int taskId) {
      return false;
    }

  }

  public static Bitmap cutCircularImage(Bitmap bitmap) {
    try {
      Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
          bitmap.getHeight(), Config.ARGB_8888);
      Canvas canvas = new Canvas(output);
      final Paint paint = new Paint();
      final Rect rect = new Rect(0, 0, bitmap.getWidth(),
          bitmap.getHeight());
      final RectF rectF = new RectF(new Rect(0, 0, bitmap.getWidth(),
          bitmap.getHeight()));
      final float roundPx = bitmap.getWidth() / 2;
      paint.setAntiAlias(true);
      canvas.drawARGB(0, 0, 0, 0);
      paint.setColor(Color.BLACK);
      canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
      paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
      final Rect src = new Rect(0, 0, bitmap.getWidth(),
          bitmap.getHeight());
      canvas.drawBitmap(bitmap, src, rect, paint);
      return output;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return bitmap;
  }

  /**
   * cut a rounded image
   * 
   * @param cornerSize
   * @param bitmap
   * @return
   */
  public static Bitmap cutRoundedImage(int cornerSize, Bitmap bitmap) {
    try {
      // final int th = 32;
      // final int tp = 16;
      final Paint paint = new Paint();
      paint.setAntiAlias(true);
      paint.setStyle(Paint.Style.FILL_AND_STROKE);
      paint.setColor(Color.BLACK);
      Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
          bitmap.getHeight(), Config.ARGB_8888);
      final int bw = bitmap.getWidth();
      final int bh = bitmap.getHeight();
      Canvas canvas = new Canvas(output);
      final Rect des = new Rect(0, 0, bw, bh);
      final Rect src = new Rect(0, 0, bw, bh);
      canvas.drawARGB(0, 0, 0, 0);
      final RectF rectF = new RectF(new Rect(0, 0, (cornerSize << 1) + 8,
          bh));
      Path p = new Path();
      p.setFillType(Path.FillType.WINDING);
      final int rrx = cornerSize + 4;

      // p.moveTo(rrx, 0);
      // p.lineTo(bw, 0);
      // final int t1 = bh - th - tp;
      // p.lineTo(bw, t1);
      // p.lineTo(bw - (int) (th * 0.866), t1 + (th >> 1));
      // p.lineTo(bw, bh - tp);
      // p.lineTo(bw, bh);
      // p.lineTo(rrx, bh);
      // p.lineTo(rrx, 0);
      // p.close();
      p.addRect(rrx, 0, bw, bh, Path.Direction.CW);
      p.addRoundRect(rectF, cornerSize, cornerSize, Path.Direction.CW);

      canvas.drawPath(p, paint);
      paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
      canvas.drawBitmap(bitmap, src, des, paint);
      return output;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return bitmap;
  }

  public static Bitmap getRoundedImage(int cornerSize, Bitmap bitmap) {
    try {
      final Paint paint = new Paint();
      paint.setAntiAlias(true);
      paint.setStyle(Paint.Style.FILL_AND_STROKE);
      paint.setColor(Color.BLACK);
      Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
          bitmap.getHeight(), Config.ARGB_8888);
      final int bw = bitmap.getWidth();
      final int bh = bitmap.getHeight();
      Canvas canvas = new Canvas(output);
      final Rect des = new Rect(0, 0, bw, bh);
      final Rect src = new Rect(0, 0, bw, bh);
      canvas.drawARGB(0, 0, 0, 0);
      final RectF rectF = new RectF(new Rect(0, 0, bw, bh));
      canvas.drawRoundRect(rectF, cornerSize, cornerSize, paint);
      paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
      canvas.drawBitmap(bitmap, src, des, paint);
      return output;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return bitmap;
  }

  private class DownloadTask implements IPriorityTask {
    String filename;
    String urlString;
    private final ArrayList<IDownloadHandler> listeners;
    private final boolean isCancled = false;

    // IDownloadHandler tl;

    public DownloadTask(String url, String filename,
        IDownloadHandler listener) {
      this.filename = filename;
      this.urlString = url;
      // tl = listener;
      listeners = new ArrayList<IDownloadHandler>();
      listeners.add(listener);
    }

    @Override
    public String getFlag() {
      return urlString;
    }

    @Override
    public boolean onRepeatPut(IPriorityTask newTask) {
      DownloadTask nt = (DownloadTask) newTask;
      ArrayList<IDownloadHandler> listener = nt.getListener();
      if (listener != null) {
        synchronized (listeners) {
          for (IDownloadHandler l : listener) {
            if (!listeners.contains(l)) {
              listeners.add(l);
            }
          }
        }
      }
      return true;
    }

    public ArrayList<IDownloadHandler> getListener() {
      return listeners;
    }

    @Override
    public void run() {
      if (listeners != null) {
        synchronized (listeners) {
          for (IDownloadHandler tl : listeners) {
            if (tl != null)
              tl.onStart();
          }
        }
      }
      boolean storeInFile = false;
      Bitmap bitmap = null;
      try {
        // exist sdcard.
        if (storeInFile = (!TextUtils.isEmpty(storePath))) {
          downloadInFile();
        } else {
          bitmap = downloadInMemory();
        }

      } catch (IOException e) {
        if (listeners != null) {
          synchronized (listeners) {
            for (IDownloadHandler tl : listeners) {
              if (tl != null) {
                tl.onError();
              }
            }
          }
        }
        return;
      }
      if (storeInFile && cleanCache) {
        cleanSDcard();
      }
      if (listeners != null) {
        synchronized (listeners) {
          for (IDownloadHandler tl : listeners) {
            if (storeInFile) {
              tl.onFinish();
            } else {
              tl.onFinishNoFile(bitmap);
            }
          }
        }
      }
    }

    private void downloadInFile() throws IOException {
      /**
       * Workaround for bug pre-Froyo, see here for more info:
       * http://android
       * -developers.blogspot.com/2011/09/androids-http-clients.html
       */
      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
        System.setProperty("http.keepAlive", "false");
      }
      DHttpClient client = new DHttpClient();
      File cacheFile = new File(storePath, filename);
      if (!cacheFile.exists()) {
        cacheFile.createNewFile();
      }
      client.downloadInFile(urlString, cacheFile, mContext);
    }

    private Bitmap downloadInMemory() throws IOException {
      /**
       * Workaround for bug pre-Froyo, see here for more info:
       * http://android
       * -developers.blogspot.com/2011/09/androids-http-clients.html
       */
      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
        System.setProperty("http.keepAlive", "false");
      }
      DHttpClient client = new DHttpClient();
      InputStream is = client.downloadInMemory(urlString, mContext);
      return is == null ? null : BitmapFactory.decodeStream(is);
    }

    @Override
    public void isolateFlag() {

    }

    @Override
    public boolean unregisterListener(int taskId) {
      return false;
    }

  }

  /**
   * A custom Drawable that will be attached to the imageView while the work
   * is in progress. Contains a reference to the actual worker task, so that
   * it can be stopped if a new binding is required, and makes sure that only
   * the last started worker process can bind its result, independently of the
   * finish order.
   */
  static class AsyncDrawable extends BitmapDrawable {
    private final WeakReference<SearchTask> task;

    public AsyncDrawable(Resources res, Bitmap bitmap,
        SearchTask bitmapWorkerTask) {
      super(res, bitmap);
      task = new WeakReference<SearchTask>(bitmapWorkerTask);
    }

    public AsyncDrawable(Resources res, SearchTask bitmapWorkerTask) {
      super(res);
      task = new WeakReference<SearchTask>(bitmapWorkerTask);
    }

    public SearchTask getTask() {
      return task.get();
    }
  }

  public void restartThreadPool() {
    // searchThreadPool = null;
    searchThreadPool = DThreadPool.newThreadPool(1, 20, 5, !timeSortASC);
    // downloadThreadQueue = null;
    downloadThreadQueue = DThreadPool.newThreadPool(1, 6, 5, !timeSortASC);
  }

  protected String getTag() {
    return tag;
  }

  protected String packKey(String url, Builder builder) {
    return builder + url;
  }

  protected boolean cancelWork(boolean isBackground, String url,
      ImageView view) {
    SearchTask task = getSearchTask(isBackground, view);
    if (task != null) {
      final String taskURL = task.url;
      if ((!TextUtils.isEmpty(taskURL))
          && (taskURL.equalsIgnoreCase(url)) && (!task.stop)) {
        return false;
      } else {
        task.cancelWork();
      }
    }
    return true;
  }

  protected boolean cancelWork(boolean isBackground, ImageView view,
      String filename) {
    SearchTask task = getSearchTask(isBackground, view);
    if (task != null) {
      final String taskURL = task.filename;
      if ((!TextUtils.isEmpty(taskURL))
          && (taskURL.equalsIgnoreCase(filename)) && (!task.stop)) {
        return false;
      } else {
        task.cancelWork();
      }
    }
    return true;
  }

  protected boolean cancelWork(boolean isBackground, ImageView view) {
    SearchTask task = getSearchTask(isBackground, view);
    if (task != null) {
      task.cancelWork();
    }
    return true;
  }

  private static SearchTask getSearchTask(boolean isBackground,
      ImageView imageView) {
    if (imageView != null) {
      final Drawable drawable = isBackground ? imageView.getBackground()
          : imageView.getDrawable();
      if (drawable instanceof AsyncDrawable) {
        final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
        return asyncDrawable.getTask();
      }
    }
    return null;
  }

  public static String getFileName(String url) {
    String key = MD5Util.getStringMD5(url);
    if (url.endsWith(".gif") || (url.endsWith(".GIF"))) {
      key += GIF_END;
    }
    return key;
  }

  private static synchronized Bitmap decodeBitmap(String filename, int width,
      int height, boolean isScale) {
    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    // final String filename = file.getAbsolutePath();
    BitmapFactory.decodeFile(filename, options);
    if (options.outWidth < 1 || options.outHeight < 1) {
      String fn = filename;
      File ft = new File(fn);
      if (ft.exists()) {
        ft.delete();
        return null;
      }
    }

    // Calculate inSampleSize
    options.inSampleSize = calculateOriginal(options, width, height);
    if (options.inSampleSize == 3) {
      options.inSampleSize = 4;
    }
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    options.inPreferredConfig = Config.RGB_565;
    Bitmap bm1 = null;
    try {
      bm1 = BitmapFactory.decodeFile(filename, options);
    } catch (OutOfMemoryError oom) {
      oom.printStackTrace();
      System.gc();
    }
    if (bm1 == null) {
      return null;
    }
    if (!isScale) {
      return bm1;
    }
    int queryWidth = width;
    int queryHeight = height;
    int resWidth = bm1.getWidth();
    int resHeight = bm1.getHeight();
    float scaleWidth = ((float) queryWidth) / resWidth;
    float scaleHeight = ((float) queryHeight) / resHeight;
    Bitmap bm;
    try {
      if (scaleWidth >= 1 && scaleHeight >= 1) {
        bm = bm1;
      } else if (scaleHeight >= 1 && scaleWidth < 1) {
        int cutH = resHeight;
        int cutW = queryWidth * cutH / queryHeight;
        // int cutY = 0;
        int cutX = resWidth / 2 - cutW / 2;
        bm = Bitmap.createBitmap(bm1, cutX, 0, cutW, cutH);
      } else if (scaleWidth >= 1 && scaleHeight < 1) {
        int cutW = resWidth;
        int cutH = queryHeight * cutW / queryWidth;
        // int cutX = 0;
        // int cutY = resHeight / 2 - cutH / 2;
        bm = Bitmap.createBitmap(bm1, 0, 0, cutW, cutH);
      } else {
        float scale = scaleHeight < scaleWidth ? scaleWidth
            : scaleHeight;
        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale);
        bm = Bitmap.createBitmap(bm1, 0, 0, resWidth, resHeight,
            matrix, true);
      }
    } catch (Exception e) {
      bm = bm1;
    }
    return bm;
  }

  private static int calculateOriginal(BitmapFactory.Options options,
      int reqWidth, int reqHeight) {
    int inSampleSize = 1;
    final int height = options.outHeight;
    final int width = options.outWidth;
    if (reqWidth < 0 || reqHeight < 0) {
      return 1;
    }
    if (height > reqHeight || width > reqWidth) {
      if (width > height) {
        inSampleSize = Math.round((float) height / (float) reqHeight);
      } else {
        inSampleSize = Math.round((float) width / (float) reqWidth);
      }
      final float totalPixels = width * height;
      final float totalReqPixelsCap = reqWidth * reqHeight * 3;

      while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
        inSampleSize++;
      }
    }
    return inSampleSize;
  }

  private void cleanSDcard() {
    new Thread() {
      @Override
      public void run() {
        File dir = new File(storePath);
        File[] files = dir.listFiles();
        if (files == null) {
          return;
        }
        long dirSize = 0;
        for (File tf : files) {
          dirSize += tf.length();
        }
        long sdFree = (getUsableSpace(dir)) - dirSize;
        if ((sdFree < MIN_CACHE_SIZE) || (dirSize >= MAX_CACHE_SIZE)) {
          cleanCacheInDisk(files);
          // notify user to clean Cache.
          // CleanSDDialog.launch(context);
        }
      }
    }.start();
  }

  private static synchronized int cleanCacheInDisk(File... files) {
    // File[] files = dir.listFiles();
    if (files == null) {
      return 0;
    }
    int result = 0;
    int removeFactor = (int) ((PERCENT_CLEAN * files.length) + 1);
    Arrays.sort(files, new FileLastModifSort());
    for (int i = 0; i < removeFactor; i++) {
      if (files[i].delete()) {
        result++;
      }
    }
    return result;
  }

  public void reserLoader() {
    synchronized (restartLock) {
      this.onScreen = false;
      mCache.cleanCache();
      searchThreadPool.shutdownNow();
      downloadThreadQueue.shutdownNow();
      // downloadThreadQueue.stopQueue(tag);
      restartThreadPool();
      this.onScreen = true;
    }
  }

  public int cleanDiskCache() {
    int result = 0;
    File dir = new File(storePath);
    File[] files = dir.listFiles();
    for (File f : files) {
      if (f.delete()) {
        result++;
      }
    }
    return result;
  }

  public void cleanMemoryCache() {
    mCache.cleanCache();
  }

  private static long getUsableSpace(File path) {
    final StatFs stats = new StatFs(path.getPath());
    return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();
  }

  public static boolean judgeGIF(String filename) {
    return (filename.endsWith(CacheWorker.GIF_END))
        || (filename.endsWith(".gif")) || (filename.endsWith(".GIF"));
  }

  public static String getCacheFolder(Context mContext, String cacheDir) {
    File cacheFileDir;
    if (!Environment.getExternalStorageState().equals(
        Environment.MEDIA_MOUNTED)) {
      cacheFileDir = mContext.getCacheDir();
      cacheFileDir = new File(cacheFileDir, "imgcache");
      if (!cacheFileDir.exists())
        cacheFileDir.mkdir();
    } else {
      File fExternalStorageDirectory = Environment
          .getExternalStorageDirectory();
      String str = null;
      if (!TextUtils.isEmpty(cacheDir)) {
        str = cacheDir;
      } else {
        str = "childhood";
      }
      File catchFileDir = new File(fExternalStorageDirectory, str);
      if (!catchFileDir.exists()) {
        catchFileDir.mkdir();
      }
      File imageCacheDir = new File(catchFileDir, "imagecache");
      if (!imageCacheDir.exists()) {
        imageCacheDir.mkdir();
      }
      cacheFileDir = imageCacheDir;
    }
    return cacheFileDir.getAbsolutePath();
  }

  public static class Builder {
    // Required parameters
    private final int imageWidth;
    private final int imageHeight;

    // Optional parameters
    private boolean isScale = false;
    // if True, will create a Circular Image, and ignore spRounded.
    private boolean needRounded = false;
    // if spRounded>0, and needRounded = false, will create a rounded Image.
    private int spRounded = -1;
    // If engine handle GIF
    private boolean supportGIF = true;
    //
    private int loadingImage = -1;

    private boolean greyImage = false;

    private boolean needRotation = false;

    private String cacheDir = "childhood";

    public Builder(int imageWidth, int imageHeight) {
      this.imageHeight = imageHeight;
      this.imageWidth = imageWidth;
    }

    @Override
    public String toString() {
      return "Builder{" + "imageWidth=" + imageWidth + ", imageHeight="
          + imageHeight + ", isScale=" + isScale + ", needRounded="
          + needRounded + ", spRounded=" + spRounded
          + ", supportGIF=" + supportGIF + ", loadingImage="
          + loadingImage + ", greyImage=" + greyImage + '}';
    }

    public Builder isScale(boolean value) {
      isScale = value;
      return this;
    }

    public Builder needRounded(boolean value) {
      needRounded = value;
      return this;
    }

    public Builder needRotation(boolean value) {
      needRotation = value;
      return this;
    }

    public Builder setSoundedSP(int value) {
      spRounded = value;
      return this;
    }

    public Builder supportGIF(boolean value) {
      supportGIF = value;
      return this;
    }

    public Builder setLoadingImage(int resId) {
      loadingImage = resId;
      return this;
    }

    public Builder setGreyImage(boolean enableGrey) {
      greyImage = enableGrey;
      return this;
    }

    public Builder setCacheDir(String cacheDir) {
      this.cacheDir = cacheDir;
      return this;
    }
  }
}




Java Source Code List

com.sunny.cache.BaseLoadListener.java
com.sunny.cache.CacheWorker.java
com.sunny.cache.DiskLruCache.java
com.sunny.cache.FileLastModifSort.java
com.sunny.cache.GIFDecoder.java
com.sunny.cache.IDownloadHandler.java
com.sunny.cache.MemoryCache.java
com.sunny.cache.OnSetImageListener.java
com.sunny.cache.RecyclingBitmapDrawable.java
com.sunny.cache.ThumbnailLoader.java
com.sunny.net.DHttpClient.java
com.sunny.net.ProxyUtil.java
com.sunny.threadpool.AbstractCommand.java
com.sunny.threadpool.CommandFactory.java
com.sunny.threadpool.DThreadPool.java
com.sunny.threadpool.IDThreadPool.java
com.sunny.threadpool.IPriorityTask.java
com.sunny.threadpool.ITaskHandler.java
com.sunny.threadpool.PriorityTask.java
com.sunny.threadpool.PriorityThreadFactory.java
com.sunny.threadpool.TaskPriority.java
com.sunny.util.ImageUtil.java
com.sunny.util.MD5Util.java
com.sunny.util.Utils.java