Android Open Source - QBShare-Android Q B Image Loader






From Project

Back to project page QBShare-Android.

License

The source code is released under:

Copyright (c) 2011 QBurst, http://qburst.com/ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redi...

If you think the Android project QBShare-Android 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.qmcommerce.android.utils;
//  w w  w  .j ava2s  .  c o m
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Stack;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.widget.ImageView;

public class QBImageLoader {

  // the simplest in-memory cache implementation. This should be replaced with
  // something like SoftReference or BitmapOptions.inPurgeable(since 1.6)
  private static HashMap<String, Bitmap> cache = new HashMap<String, Bitmap>();

  private File cacheDir;

  private boolean _isSampling = true;

  private QBImageLoaderListener _imgLoadListener = null;

  private static final long DEFAULT_EXPIRY = 24 * 3600 * 1000; // Default
  // expiry = 4
  // Hours.

  private Context _context = null;

  public QBImageLoader(Context context, QBImageLoaderListener imgLoadListener) {

    _imgLoadListener = imgLoadListener;
    _context = context;
    initLoader(context);
  }

  public QBImageLoader(Context context) {
    initLoader(context);
    _context = context;
  }

  private void initLoader(Context context) {
    // Make the background thead low priority. This way it will not affect
    // the UI performance
    photoLoaderThread.setPriority(Thread.NORM_PRIORITY - 1);

    // Find the dir to save cached images
    if (android.os.Environment.getExternalStorageState().equals(
        android.os.Environment.MEDIA_MOUNTED))
      cacheDir = new File(android.os.Environment
          .getExternalStorageDirectory(), "dtcm_cache");
    else
      cacheDir = context.getCacheDir();
    if (!cacheDir.exists())
      cacheDir.mkdirs();

  }

  private boolean isImageExpired(String url) {
    // I identify images by hashcode. Not a perfect solution, good for the
    // demo.
    String filename = String.valueOf(url.hashCode());
    File f = new File(cacheDir, filename);
    long now = System.currentTimeMillis();
    if (f.exists()) {
      if ((now - f.lastModified()) > DEFAULT_EXPIRY) {

        Log.d("ImageLoader_Cache", "Image has been Expired");
        cache.remove(url);
        f.delete();
        return true;
      } else {
        Log.d("ImageLoader_Cache", "Image has not been been Expired!");
        return false;
      }
    } else {
      return true;
    }
  }

  public void displayImage(String url, Activity activity, ImageView imageView) {
    if (cache.containsKey(url)) {
      if (!isImageExpired(url)) {
        imageView.setImageBitmap(cache.get(url));

        if (_imgLoadListener != null)
          _imgLoadListener.imageLoadComplete(cache.get(url));

      } else {
        queuePhoto(url, activity, imageView);
      }

    } else {
      queuePhoto(url, activity, imageView);
    }
  }

  public void displayImage(String url, Activity activity,
      ImageView imageView, Boolean sampling) {
    this._isSampling = sampling;

    this.displayImage(url, activity, imageView);
    /*
     * if(cache.containsKey(url)) {
     * imageView.setImageBitmap(cache.get(url));
     * 
     * } else { queuePhoto(url, activity, imageView); }
     */
  }

  private void queuePhoto(String url, Activity activity, ImageView imageView) {
    // This ImageView may be used for other images before. So there may be
    // some old tasks in the queue. We need to discard them.
    photosQueue.Clean(imageView);
    PhotoToLoad p = new PhotoToLoad(url, imageView);
    synchronized (photosQueue.photosToLoad) {
      photosQueue.photosToLoad.push(p);
      photosQueue.photosToLoad.notifyAll();
    }

    // start thread if it's not started yet
    if (photoLoaderThread.getState() == Thread.State.NEW)
      photoLoaderThread.start();
  }

  private Bitmap getBitmap(String url) {
    // I identify images by hashcode. Not a perfect solution, good for the
    // demo.
    String filename = String.valueOf(url.hashCode());
    File f = new File(cacheDir, filename);
    // from SD cache
    if (!isImageExpired(url)) {
      Bitmap b = decodeFile(f);
      if (b != null)
        return b;
    }

    // from web
    try {
      Bitmap bitmap = null;
      InputStream is = new URL(url).openStream();
      OutputStream os = new FileOutputStream(f);
      CopyStream(is, os);
      os.close();
      bitmap = decodeFile(f);
      return bitmap;
    } catch (Exception ex) {
      Log.d("ImageLoader", "Malformed URL : " + url);
      Log.e(ex.getClass().getName() + ": onResponseReceived",
          "Malformed URL : ", ex);
      return null;
    }
  }

  // decodes image and scales it to reduce memory consumption
  private Bitmap decodeFile(File f) {
    try {
      // decode image size
      BitmapFactory.Options o = new BitmapFactory.Options();
      o.inJustDecodeBounds = true;
      BitmapFactory.decodeStream(new FileInputStream(f), null, o);

      // Find the correct scale value. It should be the power of 2.
      final int REQUIRED_SIZE = 70;
      int width_tmp = o.outWidth, height_tmp = o.outHeight;
      int scale = 1;
      while (true) {
        if (width_tmp / 2 < REQUIRED_SIZE
            || height_tmp / 2 < REQUIRED_SIZE)
          break;
        width_tmp /= 2;
        height_tmp /= 2;
        scale *= 2;
      }

      // decode with inSampleSize
      BitmapFactory.Options o2 = new BitmapFactory.Options();
      o2.inSampleSize = scale;
      if (_isSampling)
        return BitmapFactory.decodeStream(new FileInputStream(f), null,
            o2);
      else
        try {
          return BitmapFactory.decodeStream(new FileInputStream(f),
              null, null);
        } catch (OutOfMemoryError ex) {
          QBImageLoader.clearImageCache();
          System.gc();

        }

    } catch (FileNotFoundException e) {
    }
    return null;
  }

  // Task for the queue
  private class PhotoToLoad {
    public String url;
    public ImageView imageView;

    public PhotoToLoad(String u, ImageView i) {
      url = u;
      imageView = i;
    }
  }

  PhotosQueue photosQueue = new PhotosQueue();

  public void stopThread() {
    photoLoaderThread.interrupt();
  }

  // stores list of photos to download
  class PhotosQueue {
    private Stack<PhotoToLoad> photosToLoad = new Stack<PhotoToLoad>();

    // removes all instances of this ImageView
    public void Clean(ImageView image) {
      for (int j = 0; j < photosToLoad.size();) {
        if (photosToLoad.get(j).imageView == image)
          try {
            photosToLoad.remove(j);
          } catch (ArrayIndexOutOfBoundsException aex) {
            Log.e(aex.getClass().getName() + ": Clean", aex
                .getMessage(), aex);
          }
        else
          ++j;
      }
    }
  }

  class PhotosLoader extends Thread {
    public void run() {
      try {
        while (true) {
          // thread waits until there are any images to load in the
          // queue
          if (photosQueue.photosToLoad.size() == 0)
            synchronized (photosQueue.photosToLoad) {
              photosQueue.photosToLoad.wait();
            }
          if (photosQueue.photosToLoad.size() != 0) {
            PhotoToLoad photoToLoad;
            synchronized (photosQueue.photosToLoad) {
              photoToLoad = photosQueue.photosToLoad.pop();
            }
            Bitmap bmp = getBitmap(photoToLoad.url);
            Log.d("Image_loader", "URL : " + photoToLoad.url);
            cache.put(photoToLoad.url, bmp);
            Object tag = photoToLoad.imageView.getTag();
            if (tag != null
                && ((String) tag).equals(photoToLoad.url)) {
              BitmapDisplayer bd = new BitmapDisplayer(bmp,
                  photoToLoad.imageView);
              Activity a = (Activity) photoToLoad.imageView
                  .getContext();
              a.runOnUiThread(bd);
            }
          }
          if (Thread.interrupted())
            break;
        }
      } catch (InterruptedException e) {
        // allow thread to exit
      }
    }
  }

  PhotosLoader photoLoaderThread = new PhotosLoader();

  // Used to display bitmap in the UI thread
  class BitmapDisplayer implements Runnable {
    Bitmap bitmap;
    ImageView imageView;

    public BitmapDisplayer(Bitmap b, ImageView i) {
      bitmap = b;
      imageView = i;
    }

    public void run() {
      imageView.setImageBitmap(null);
      if (bitmap != null) {
        imageView.setImageBitmap(bitmap);
        Log.d("IMAGEVIEW_TAG", imageView.getTag().toString());
        // Let the implementer know that the bitmap has been loaded.
        if (_imgLoadListener != null)
          _imgLoadListener.imageLoadComplete(bitmap);
      }

    }
  }

  public static void clearImageCache() {
    for (int i = 0; i < cache.size(); i++) {
      Bitmap bm = cache.get(i);
      if (bm != null) {
        bm.recycle();
        bm = null;
      }
    }
    cache.clear();
  }

  public void clearCache() {
    // clear memory cache
    cache.clear();

    // clear SD cache
    File[] files = cacheDir.listFiles();
    for (File f : files)
      f.delete();
  }

  public static void CopyStream(InputStream is, OutputStream os) {
    final int buffer_size = 1024;
    try {
      byte[] bytes = new byte[buffer_size];
      for (;;) {
        int count = is.read(bytes, 0, buffer_size);
        if (count == -1)
          break;
        os.write(bytes, 0, count);
      }
    } catch (Exception ex) {
    }
  }

}




Java Source Code List

com.qburst.android.facebook.AsyncFacebookRunner.java
com.qburst.android.facebook.BaseDialogListener.java
com.qburst.android.facebook.BaseRequestListener.java
com.qburst.android.facebook.DialogError.java
com.qburst.android.facebook.FacebookError.java
com.qburst.android.facebook.Facebook.java
com.qburst.android.facebook.FbDialog.java
com.qburst.android.facebook.SessionEvents.java
com.qburst.android.facebook.SessionStore.java
com.qburst.android.facebook.Util.java
com.qburst.android.interfaces.share.QBShareListener.java
com.qburst.android.interfaces.share.QBShareManager.java
com.qburst.android.interfaces.share.QBShare.java
com.qburst.android.linkedin.AsyncLinkedInRunner.java
com.qburst.android.linkedin.DialogError.java
com.qburst.android.linkedin.LinkedInConstants.java
com.qburst.android.linkedin.LinkedInError.java
com.qburst.android.linkedin.LinkedIn.java
com.qburst.android.linkedin.LnDialog.java
com.qburst.android.linkedin.Util.java
com.qburst.android.twitter.AsyncTwitterRunner.java
com.qburst.android.twitter.DialogError.java
com.qburst.android.twitter.TwDialog.java
com.qburst.android.twitter.TwitterConstants.java
com.qburst.android.twitter.TwitterError.java
com.qburst.android.twitter.Twitter.java
com.qburst.android.twitter.Util.java
com.qburst.config.QBShareConstants.java
com.qburst.share.activities.QBShareActivity.java
com.qburst.share.activities.QBShareFacebook.java
com.qburst.share.activities.QBShareTwitter.java
com.qburst.share.activities.QMShareLinkedIn.java
com.qmcommerce.android.utils.QBImageLoaderListener.java
com.qmcommerce.android.utils.QBImageLoader.java