package com.jmheart.adapter;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
public class ImageLoader
{
/**
* ͼƬ����ĺ�����
*/
private LruCache<String, Bitmap> mLruCache;
/**
* �̳߳�
*/
private ExecutorService mThreadPool;
/**
* �̳߳ص��߳�������Ĭ��Ϊ1
*/
private int mThreadCount = 1;
/**
* ���еĵ��ȷ�ʽ
*/
private Type mType = Type.LIFO;
/**
* �������
*/
private LinkedList<Runnable> mTasks;
/**
* ��ѯ���߳�
*/
private Thread mPoolThread;
private Handler mPoolThreadHander;
/**
* ������UI�̵߳�handler�����ڸ�ImageView����ͼƬ
*/
private Handler mHandler;
/**
* ����һ��ֵΪ1���ź�������ֹmPoolThreadHanderδ��ʼ�����
*/
private volatile Semaphore mSemaphore = new Semaphore(1);
/**
* ����һ��ֵΪ1���ź����������̳߳��ڲ�Ҳ��һ�������̣߳���ֹ����������ٶȹ��죬ʹLIFOЧ��������
*/
private volatile Semaphore mPoolSemaphore;
private static ImageLoader mInstance;
/**
* ���еĵ��ȷ�ʽ
*
* @author zhy
*
*/
public enum Type
{
FIFO, LIFO
}
/**
* ������ø�ʵ������
*
* @return
*/
public static ImageLoader getInstance()
{
if (mInstance == null)
{
synchronized (ImageLoader.class)
{
if (mInstance == null)
{
mInstance = new ImageLoader(1, Type.LIFO);
}
}
}
return mInstance;
}
private ImageLoader(int threadCount, Type type)
{
init(threadCount, type);
}
private void init(int threadCount, Type type)
{
// loop thread
mPoolThread = new Thread()
{
@Override
public void run()
{
try
{
// ����һ���ź���
mSemaphore.acquire();
} catch (InterruptedException e)
{
}
Looper.prepare();
mPoolThreadHander = new Handler()
{
@Override
public void handleMessage(Message msg)
{
mThreadPool.execute(getTask());
try
{
mPoolSemaphore.acquire();
} catch (InterruptedException e)
{
}
}
};
// �ͷ�һ���ź���
mSemaphore.release();
Looper.loop();
}
};
mPoolThread.start();
// ��ȡӦ�ó����������ڴ�
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 8;
mLruCache = new LruCache<String, Bitmap>(cacheSize)
{
@Override
protected int sizeOf(String key, Bitmap value)
{
return value.getRowBytes() * value.getHeight();
};
};
mThreadPool = Executors.newFixedThreadPool(threadCount);
mPoolSemaphore = new Semaphore(threadCount);
mTasks = new LinkedList<Runnable>();
mType = type == null ? Type.LIFO : type;
}
/**
* ����ͼƬ
*
* @param path
* @param imageView
*/
public void loadImage(final String path, final ImageView imageView)
{
// set tag
imageView.setTag(path);
// UI�߳�
if (mHandler == null)
{
mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
ImgBeanHolder holder = (ImgBeanHolder) msg.obj;
ImageView imageView = holder.imageView;
Bitmap bm = holder.bitmap;
String path = holder.path;
if (imageView.getTag().toString().equals(path))
{
imageView.setImageBitmap(bm);
}
}
};
}
Bitmap bm = getBitmapFromLruCache(path);
if (bm != null)
{
ImgBeanHolder holder = new ImgBeanHolder();
holder.bitmap = bm;
holder.imageView = imageView;
holder.path = path;
Message message = Message.obtain();
message.obj = holder;
mHandler.sendMessage(message);
} else
{
addTask(new Runnable()
{
@Override
public void run()
{
ImageSize imageSize = getImageViewWidth(imageView);
int reqWidth = imageSize.width;
int reqHeight = imageSize.height;
Bitmap bm = decodeSampledBitmapFromResource(path, reqWidth,
reqHeight);
addBitmapToLruCache(path, bm);
ImgBeanHolder holder = new ImgBeanHolder();
holder.bitmap = getBitmapFromLruCache(path);
holder.imageView = imageView;
holder.path = path;
Message message = Message.obtain();
message.obj = holder;
// Log.e("TAG", "mHandler.sendMessage(message);");
mHandler.sendMessage(message);
mPoolSemaphore.release();
}
});
}
}
/**
* ���һ������
*
* @param runnable
*/
private synchronized void addTask(Runnable runnable)
{
try
{
// �����ź�������ֹmPoolThreadHanderΪnull
if (mPoolThreadHander == null)
mSemaphore.acquire();
} catch (InterruptedException e)
{
}
mTasks.add(runnable);
mPoolThreadHander.sendEmptyMessage(0x110);
}
/**
* ȡ��һ������
*
* @return
*/
private synchronized Runnable getTask()
{
if (mType == Type.FIFO)
{
return mTasks.removeFirst();
} else if (mType == Type.LIFO)
{
return mTasks.removeLast();
}
return null;
}
/**
* ������ø�ʵ������
*
* @return
*/
public static ImageLoader getInstance(int threadCount, Type type)
{
if (mInstance == null)
{
synchronized (ImageLoader.class)
{
if (mInstance == null)
{
mInstance = new ImageLoader(threadCount, type);
}
}
}
return mInstance;
}
/**
* ����ImageView����ʵ���ѹ���Ŀ��
*
* @param imageView
* @return
*/
private ImageSize getImageViewWidth(ImageView imageView)
{
ImageSize imageSize = new ImageSize();
final DisplayMetrics displayMetrics = imageView.getContext()
.getResources().getDisplayMetrics();
final LayoutParams params = imageView.getLayoutParams();
int width = params.width == LayoutParams.WRAP_CONTENT ? 0 : imageView
.getWidth(); // Get actual image width
if (width <= 0)
width = params.width; // Get layout width parameter
if (width <= 0)
width = getImageViewFieldValue(imageView, "mMaxWidth"); // Check
// maxWidth
// parameter
if (width <= 0)
width = displayMetrics.widthPixels;
int height = params.height == LayoutParams.WRAP_CONTENT ? 0 : imageView
.getHeight(); // Get actual image height
if (height <= 0)
height = params.height; // Get layout height parameter
if (height <= 0)
height = getImageViewFieldValue(imageView, "mMaxHeight"); // Check
// maxHeight
// parameter
if (height <= 0)
height = displayMetrics.heightPixels;
imageSize.width = width;
imageSize.height = height;
return imageSize;
}
/**
* ��LruCache�л�ȡһ��ͼƬ����������ھͷ���null��
*/
private Bitmap getBitmapFromLruCache(String key)
{
return mLruCache.get(key);
}
/**
* ��LruCache�����һ��ͼƬ
*
* @param key
* @param bitmap
*/
private void addBitmapToLruCache(String key, Bitmap bitmap)
{
if (getBitmapFromLruCache(key) == null)
{
if (bitmap != null)
mLruCache.put(key, bitmap);
}
}
/**
* ����inSampleSize������ѹ��ͼƬ
*
* @param options
* @param reqWidth
* @param reqHeight
* @return
*/
private int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight)
{
// ԴͼƬ�Ŀ��
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1;
if (width > reqWidth && height > reqHeight)
{
// �����ʵ�ʿ�Ⱥ�Ŀ���ȵı���
int widthRatio = Math.round((float) width / (float) reqWidth);
int heightRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = Math.max(widthRatio, heightRatio);
}
return inSampleSize;
}
/**
* ���ݼ����inSampleSize���õ�ѹ����ͼƬ
*
* @param pathName
* @param reqWidth
* @param reqHeight
* @return
*/
private Bitmap decodeSampledBitmapFromResource(String pathName,
int reqWidth, int reqHeight)
{
// ��һ�ν�����inJustDecodeBounds����Ϊtrue������ȡͼƬ��С
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
// �������涨��ķ�������inSampleSizeֵ
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// ʹ�û�ȡ����inSampleSizeֵ�ٴν���ͼƬ
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(pathName, options);
return bitmap;
}
private class ImgBeanHolder
{
Bitmap bitmap;
ImageView imageView;
String path;
}
private class ImageSize
{
int width;
int height;
}
/**
* ������ImageView���õ�����Ⱥ߶�
*
* @param object
* @param fieldName
* @return
*/
private static int getImageViewFieldValue(Object object, String fieldName)
{
int value = 0;
try
{
Field field = ImageView.class.getDeclaredField(fieldName);
field.setAccessible(true);
int fieldValue = (Integer) field.get(object);
if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE)
{
value = fieldValue;
Log.e("TAG", value + "");
}
} catch (Exception e)
{
}
return value;
}
}