Android Open Source - yammp Lazy Image Loader






From Project

Back to project page yammp.

License

The source code is released under:

GNU Lesser General Public License

If you think the Android project yammp 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 org.yammp.util;
//ww  w  . j  a  v a 2  s.c  o m
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ListView;

/**
 * Lazy image loader for {@link ListView} and {@link GridView} etc.</br> </br>
 * Inspired by <a url="https://github.com/thest1/LazyList">LazyList</a>, this
 * class has extra features like image loading/caching image to
 * /mnt/sdcard/Android/data/[package name]/cache features.</br> </br> Requires
 * Android 2.2, you can modify {@link Context#getExternalCacheDir()} to other
 * support Android 2.1 and below.
 * 
 * @author mariotaku
 * 
 */
public class LazyImageLoader {

  MemoryCache mMemoryCache = new MemoryCache();
  FileCache mFileCache;
  private Map<ImageView, Object> mImageViews = Collections
      .synchronizedMap(new WeakHashMap<ImageView, Object>());
  ExecutorService mExecutorService;
  private int mFallbackRes;

  public LazyImageLoader(Context context, int fallback) {
    mFileCache = new FileCache(context);
    mExecutorService = Executors.newFixedThreadPool(5);
    mFallbackRes = fallback;
  }

  public void clearFileCache() {
    mFileCache.clear();
  }

  public void clearMemoryCache() {
    mMemoryCache.clear();
  }

  public void displayImage(File file, ImageView imageview) {
    if (file == null) {
      imageview.setImageResource(mFallbackRes);
      return;
    }
    mImageViews.put(imageview, file);
    Bitmap bitmap = mMemoryCache.get(file);
    if (bitmap != null) {
      imageview.setImageBitmap(bitmap);
    } else {
      queuePhoto(file, imageview);
      imageview.setImageResource(mFallbackRes);
    }
  }

  public void displayImage(URL url, ImageView imageview) {
    if (url == null) {
      imageview.setImageResource(mFallbackRes);
      return;
    }
    mImageViews.put(imageview, url);
    Bitmap bitmap = mMemoryCache.get(url);
    if (bitmap != null) {
      imageview.setImageBitmap(bitmap);
    } else {
      queuePhoto(url, imageview);
      imageview.setImageResource(mFallbackRes);
    }
  }

  private 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) {
    }
  }

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

      // Find the correct scale value. It should be the power of 2.
      final int REQUIRED_SIZE = 70;
      int width_tmp = options.outWidth, height_tmp = options.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;
      return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {
    }
    return null;
  }

  private Bitmap getBitmapFromFile(File file) {
    if (file == null) return null;
    File f = mFileCache.getFile(file);

    // from SD cache
    Bitmap bitmap = decodeFile(f);

    if (bitmap != null) {
      return bitmap;
    } else {
      bitmap = decodeFile(file);
      if (bitmap == null) return null;
      try {
        FileOutputStream fos = new FileOutputStream(f);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 85, fos);
        fos.flush();
        fos.close();
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    return bitmap;

  }

  private Bitmap getBitmapFromWeb(URL url) {
    if (url == null) return null;
    File f = mFileCache.getFile(url);

    // from SD cache
    Bitmap b = decodeFile(f);
    if (b != null) return b;

    // from web
    try {
      Bitmap bitmap = null;
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
      conn.setConnectTimeout(30000);
      conn.setReadTimeout(30000);
      conn.setInstanceFollowRedirects(true);
      InputStream is = conn.getInputStream();
      OutputStream os = new FileOutputStream(f);
      copyStream(is, os);
      os.close();
      bitmap = decodeFile(f);
      return bitmap;
    } catch (Exception ex) {
      ex.printStackTrace();
      return null;
    }
  }

  private void queuePhoto(File file, ImageView imageview) {
    LocalImageToLoad p = new LocalImageToLoad(file, imageview);
    mExecutorService.submit(new LocalImageLoader(p));
  }

  private void queuePhoto(URL url, ImageView imageview) {
    WebImageToLoad p = new WebImageToLoad(url, imageview);
    mExecutorService.submit(new WebImageLoader(p));
  }

  boolean imageViewReused(LocalImageToLoad imagetoload) {
    Object tag = mImageViews.get(imagetoload.imageview);
    if (tag == null || !tag.equals(imagetoload.file)) return true;
    return false;
  }

  boolean imageViewReused(WebImageToLoad imagetoload) {
    Object tag = mImageViews.get(imagetoload.imageview);
    if (tag == null || !tag.equals(imagetoload.url)) return true;
    return false;
  }

  public class MemoryCache {

    private Map<Object, SoftReference<Bitmap>> mCache = Collections
        .synchronizedMap(new HashMap<Object, SoftReference<Bitmap>>());

    public void clear() {
      mCache.clear();
    }

    public Bitmap get(Object tag) {
      if (!mCache.containsKey(tag)) return null;
      SoftReference<Bitmap> ref = mCache.get(tag);
      return ref.get();
    }

    public void put(Object id, Bitmap bitmap) {
      mCache.put(id, new SoftReference<Bitmap>(bitmap));
    }
  }

  private class FileCache {

    private File cacheDir;

    public FileCache(Context context) {
      /* Find the dir to save cached images. */
      if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        cacheDir = context.getExternalCacheDir();
      } else {
        cacheDir = context.getCacheDir();
      }
      if (!cacheDir.exists()) cacheDir.mkdirs();
    }

    public void clear() {
      File[] files = cacheDir.listFiles();
      if (files == null) return;
      for (File f : files) {
        f.delete();
      }
    }

    /**
     * I identify images by hashcode. Not a perfect solution, good for the
     * demo.
     */
    public File getFile(Object tag) {
      String filename = String.valueOf(tag.hashCode());
      File f = new File(cacheDir, filename);
      return f;
    }

  }

  // Used to display bitmap in the UI thread
  private class LocalBitmapDisplayer implements Runnable {

    Bitmap bitmap;
    LocalImageToLoad imagetoload;

    public LocalBitmapDisplayer(Bitmap b, LocalImageToLoad p) {
      bitmap = b;
      imagetoload = p;
    }

    @Override
    public void run() {
      if (imageViewReused(imagetoload)) return;
      if (bitmap != null) {
        imagetoload.imageview.setImageBitmap(bitmap);
      } else {
        imagetoload.imageview.setImageResource(mFallbackRes);
      }
    }
  }

  private class LocalImageLoader implements Runnable {

    LocalImageToLoad imagetoload;

    LocalImageLoader(LocalImageToLoad imagetoload) {
      this.imagetoload = imagetoload;
    }

    @Override
    public void run() {
      if (imageViewReused(imagetoload) || imagetoload.file == null) return;
      Bitmap bmp = getBitmapFromFile(imagetoload.file);
      mMemoryCache.put(imagetoload.file, bmp);
      if (imageViewReused(imagetoload)) return;
      LocalBitmapDisplayer bd = new LocalBitmapDisplayer(bmp, imagetoload);
      Activity a = (Activity) imagetoload.imageview.getContext();
      a.runOnUiThread(bd);
    }
  }

  private class LocalImageToLoad {

    public File file;
    public ImageView imageview;

    public LocalImageToLoad(File file, ImageView imageview) {
      this.file = file;
      this.imageview = imageview;
    }
  }

  // Used to display bitmap in the UI thread
  private class WebBitmapDisplayer implements Runnable {

    Bitmap bitmap;
    WebImageToLoad imagetoload;

    public WebBitmapDisplayer(Bitmap b, WebImageToLoad p) {
      bitmap = b;
      imagetoload = p;
    }

    @Override
    public void run() {
      if (imageViewReused(imagetoload)) return;
      if (bitmap != null) {
        imagetoload.imageview.setImageBitmap(bitmap);
      } else {
        imagetoload.imageview.setImageResource(mFallbackRes);
      }
    }
  }

  private class WebImageLoader implements Runnable {

    WebImageToLoad imagetoload;

    WebImageLoader(WebImageToLoad imagetoload) {
      this.imagetoload = imagetoload;
    }

    @Override
    public void run() {
      if (imageViewReused(imagetoload) || imagetoload.url == null) return;
      Bitmap bmp = getBitmapFromWeb(imagetoload.url);
      mMemoryCache.put(imagetoload.url, bmp);
      if (imageViewReused(imagetoload)) return;
      WebBitmapDisplayer bd = new WebBitmapDisplayer(bmp, imagetoload);
      Activity a = (Activity) imagetoload.imageview.getContext();
      a.runOnUiThread(bd);
    }
  }

  // Task for the queue
  private class WebImageToLoad {

    public URL url;
    public ImageView imageview;

    public WebImageToLoad(URL url, ImageView imageview) {
      this.url = url;
      this.imageview = imageview;
    }
  }

}




Java Source Code List

org.yammp.Constants.java
org.yammp.MediaAppWidgetProvider4x1.java
org.yammp.MediaAppWidgetProvider4x2.java
org.yammp.MediaButtonIntentReceiver.java
org.yammp.MusicPlaybackService.java
org.yammp.app.AlbumFragment.java
org.yammp.app.AppearanceSettingsActivity.java
org.yammp.app.ArtistFragment.java
org.yammp.app.Equalizer.java
org.yammp.app.GenreFragment.java
org.yammp.app.LyricsFragment.java
org.yammp.app.MusicBrowserActivity.java
org.yammp.app.MusicBrowserFragment.java
org.yammp.app.MusicPlaybackActivity.java
org.yammp.app.MusicSettingsActivity.java
org.yammp.app.PlaylistFragment.java
org.yammp.app.PluginFragment.java
org.yammp.app.PluginsManagerActivity.java
org.yammp.app.QueryBrowserActivity.java
org.yammp.app.QueryFragment.java
org.yammp.app.TrackBrowserActivity.java
org.yammp.app.TrackFragment.java
org.yammp.dialog.DeleteDialog.java
org.yammp.dialog.PlayShortcut.java
org.yammp.dialog.PlaylistDialog.java
org.yammp.dialog.PlaylistPickerDialog.java
org.yammp.dialog.PlaylistPicker.java
org.yammp.dialog.ScanningProgress.java
org.yammp.dialog.SearchDialog.java
org.yammp.dialog.SleepTimerDialog.java
org.yammp.dialog.VerticalTextSpinnerDialog.java
org.yammp.dialog.WeekSelector.java
org.yammp.util.ColorAnalyser.java
org.yammp.util.EqualizerWrapper.java
org.yammp.util.ImageDownloader.java
org.yammp.util.LazyImageLoader.java
org.yammp.util.LyricsDownloader.java
org.yammp.util.LyricsParser.java
org.yammp.util.LyricsSplitter.java
org.yammp.util.MusicUtils.java
org.yammp.util.PreferencesEditor.java
org.yammp.util.ServiceToken.java
org.yammp.util.ShakeListener.java
org.yammp.util.SortCursor.java
org.yammp.util.VisualizerCompatAudioFX.java
org.yammp.util.VisualizerCompatScoop.java
org.yammp.util.VisualizerCompat.java
org.yammp.util.VisualizerWrapper.java
org.yammp.view.EqualizerView.java
org.yammp.view.SliderView.java
org.yammp.view.TouchPaintView.java
org.yammp.view.VerticalTextSpinner.java
org.yammp.view.VisualizerViewFftSpectrum.java
org.yammp.view.VisualizerViewWaveForm.java
org.yammp.widget.CheckableRelativeLayout.java
org.yammp.widget.RepeatingImageButton.java
org.yammp.widget.SeparatedListAdapter.java
org.yammp.widget.TextScrollView.java
org.yammp.widget.TouchInterceptor.java