Sunday 30 October 2011

ImageLoader1.java for lazyloading of images


package com.OfficeDepot;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
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.widget.ImageView;
import android.widget.Toast;

public class ImageLoader1 extends Activity {

// 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 static File cacheDir;

public ImageLoader1(Context context) {
// Make the background thead low priority. This way it will not affect
// the UI performance
photoLoaderThread.setPriority(Thread.MAX_PRIORITY);

// Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED)) {
cacheDir = new File(context.getFilesDir().getParent(), "LazyList");
}

else {
cacheDir = context.getCacheDir();

}
if (!cacheDir.exists())
cacheDir.mkdirs();
}

// final int stub_id=R.drawable.stub;
public void DisplayImage(String url, Activity activity, ImageView imageView) {
if (cache.containsKey(url)) {
imageView.setImageBitmap(cache.get(url));
} else {
queuePhoto(url, activity, imageView);
imageView.setImageResource(R.drawable.icon);
}
}

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 static 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
Bitmap b = decodeFile(f);
if (b != null)
return b;

// from web
try {
Bitmap bitmap = null;
InputStream is = new URL(url).openStream();
FlushedInputStream k = new FlushedInputStream(is);

OutputStream os = new FileOutputStream(f);
Utils.CopyStream(k, os);
os.close();
bitmap = decodeFile(f);
return bitmap;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}

// decodes image and scales it to reduce memory consumption
private static 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++;
}

// 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;
}

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

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

static PhotosQueue photosQueue = new PhotosQueue();

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

// stores list of photos to download
static 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)
photosToLoad.remove(j);
else
++j;
}
}
}

static 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);
cache.put(photoToLoad.url, bmp);
if (((String) photoToLoad.imageView.getTag())
.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
} catch (OutOfMemoryError f) {

}
}
}

PhotosLoader photoLoaderThread = new PhotosLoader();

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

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

public void run() {
if (bitmap != null) {
imageView.setImageBitmap(bitmap);

} else {
imageView.setImageResource(R.drawable.icon);
}
}
}

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

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

static class FlushedInputStream extends FilterInputStream {

/**
* The constructor that takes in the InputStream reference.
*
* @param inputStream
*            the input stream reference.
*/
public FlushedInputStream(final InputStream inputStream) {
super(inputStream);
}

/**
* Overriding the skip method to actually skip n bytes. This
* implementation makes sure that we actually skip the n bytes no matter
* what. {@inheritDoc}
*/
@Override
public long skip(final long n) throws IOException {
long totalBytesSkipped = 0L;
// If totalBytesSkipped is equal to the required number
// of bytes to be skipped i.e. "n"
// then come out of the loop.
while (totalBytesSkipped < n) {
// Skipping the left out bytes.
long bytesSkipped = in.skip(n - totalBytesSkipped);
// If number of bytes skipped is zero then
// we need to check if we have reached the EOF
if (bytesSkipped == 0L) {
// Reading the next byte to find out whether we have reached
// EOF.
int bytesRead = read();
// If bytes read count is less than zero (-1) we have
// reached EOF.
// Cant skip any more bytes.
if (bytesRead < 0) {
break; // we reached EOF
} else {
// Since we read one byte we have actually
// skipped that byte hence bytesSkipped = 1
bytesSkipped = 1; // we read one byte
}
}
// Adding the bytesSkipped to totalBytesSkipped
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}

}

No comments:

Post a Comment