框架结构
ImageCache类(图片缓存)
流程介绍:设置了两级缓存,将最近使用的图片保存到内存中,将网络加载过来的图片保存到本地。其中保存到内存中图片,为经过压缩的图片,而保存到本地的为网络加载的原图。
保存到内存中,用到了最近最少使用算法的缓存,构造如下:
int maxMemory
= (
int)
Runtime
.getRuntime()
.maxMemory();
int cacheMemory = maxMemory / 8;
mLruCache = new LruCache<String, Bitmap>(cacheMemory) {
@Override
protected int sizeOf( String key, Bitmap value) {
//获取位图大小
return value .getByteCount();
}
};
int cacheMemory = maxMemory / 8;
mLruCache = new LruCache<String, Bitmap>(cacheMemory) {
@Override
protected int sizeOf( String key, Bitmap value) {
//获取位图大小
return value .getByteCount();
}
};
ImageNetworkUtil类(网络加载类)
只包含简单的网络获取,输入输出流操作,直接跳过。下载源代码,直接查看。
ImageCenter类(图片加载中心)
流程介绍:将加载图片任务包装到一个Runnable对象中,然后将对象添加到任务队列中,等待线程池处理任务队列中的任务。其中加载图片任务,将压缩图片方法,加载图片成功回调方法,加载图片失败回调方法都委托给了IImageHandler接口(图片处理策略)处理。
线程池构造如下:
private
static
final
int
CPU_COUNT
=
Runtime
.getRuntime()
.availableProcessors();
private static final int DEFAULT_THREAD_COUNT = CPU_COUNT + 1;
mThreadPool = Executors .newFixedThreadPool( DEFAULT_THREAD_COUNT);
private static final int DEFAULT_THREAD_COUNT = CPU_COUNT + 1;
mThreadPool = Executors .newFixedThreadPool( DEFAULT_THREAD_COUNT);
任务创建如下:
private
Runnable createTask(
final
IImageHandle imageHandle) {
return new Runnable() {
@Override
public void run() {
final Bitmap bitmap;
final String url = imageHandle .getImageUrl();
final String uid = imageHandle .getUniqueId(); //压缩后图片保存在内存中的唯一Id
String name = EncryptionUtil .getMd5(url);
//保存在内存
if (mImageCache .isExistsCache(uid)){
bitmap = mImageCache .getBitmapCache(uid);
}
//保存在本地
else if (mImageCache .isExistsDisk(name)){
byte[] bytes = mImageCache .getBitmapDisk(name);
bitmap = imageHandle .onPreHandle(bytes);
mImageCache .saveBitmapCache(uid, bitmap);
}
//网络加载
else{
byte[] bytes = ImageNetworkUtil .loadByteArrayByUrl(url);
mImageCache .saveBitmapDisk(name, bytes);
bitmap = imageHandle .onPreHandle(bytes);
mImageCache .saveBitmapCache(uid, bitmap);
}
mUIHandler .post( new Runnable() {
@Override
public void run() {
if (bitmap == null){
imageHandle .onImageLoadFailed(url);
} else {
imageHandle .onImageLoadSuccess(bitmap, url);
}
}
});
}
};
}
return new Runnable() {
@Override
public void run() {
final Bitmap bitmap;
final String url = imageHandle .getImageUrl();
final String uid = imageHandle .getUniqueId(); //压缩后图片保存在内存中的唯一Id
String name = EncryptionUtil .getMd5(url);
//保存在内存
if (mImageCache .isExistsCache(uid)){
bitmap = mImageCache .getBitmapCache(uid);
}
//保存在本地
else if (mImageCache .isExistsDisk(name)){
byte[] bytes = mImageCache .getBitmapDisk(name);
bitmap = imageHandle .onPreHandle(bytes);
mImageCache .saveBitmapCache(uid, bitmap);
}
//网络加载
else{
byte[] bytes = ImageNetworkUtil .loadByteArrayByUrl(url);
mImageCache .saveBitmapDisk(name, bytes);
bitmap = imageHandle .onPreHandle(bytes);
mImageCache .saveBitmapCache(uid, bitmap);
}
mUIHandler .post( new Runnable() {
@Override
public void run() {
if (bitmap == null){
imageHandle .onImageLoadFailed(url);
} else {
imageHandle .onImageLoadSuccess(bitmap, url);
}
}
});
}
};
}
添加和获取任务:
//任务栈
private LinkedList<Runnable> mTaskQueue = new LinkedList();
private void addTask( Runnable task) {
if (mQueueType == QueueType .LIFO){
mTaskQueue .push(task);
} else {
mTaskQueue .add(task);
}
mPoolThreadHandler .sendEmptyMessage( 0);
}
private Runnable getTask() {
if (mQueueType == QueueType .LIFO){
return mTaskQueue .pop();
} else {
return mTaskQueue .poll();
}
}
private LinkedList<Runnable> mTaskQueue = new LinkedList();
private void addTask( Runnable task) {
if (mQueueType == QueueType .LIFO){
mTaskQueue .push(task);
} else {
mTaskQueue .add(task);
}
mPoolThreadHandler .sendEmptyMessage( 0);
}
private Runnable getTask() {
if (mQueueType == QueueType .LIFO){
return mTaskQueue .pop();
} else {
return mTaskQueue .poll();
}
}
IImageHandle接口(图片处理策略类)
单单罗列出了几个简单的接口,通过实现这些接口,来生成不同的图片处理策略。接下来,会展示一个我自己实现的图片处理策略,读者感兴趣的话,也可以写几个自己看着说的实现类。
接口结构及其功能描述如下:
public
interface
IImageHandle {
/**
* 获取处理后得到的图片的唯一id
* (建议:将与图片处理有关的所有因素都结合组成一个MD5码)
*
* @return 唯一id
*/
String getUniqueId();
/**
* 获取图片地址
* @return 图片地址
*/
String getImageUrl();
/**
* 处理图片
* @param bytes 原始图片字节码
* @return 处理后图片
*/
Bitmap onPreHandle( byte[] bytes);
/**
* 图片加载成功回调
* @param bitmap 最终图片
* @param url 图片地址
*/
void onImageLoadSuccess( Bitmap bitmap, String url);
/**
* 图片加载成功回调
* @param url 图片地址
*/
void onImageLoadFailed( String url);
}
/**
* 获取处理后得到的图片的唯一id
* (建议:将与图片处理有关的所有因素都结合组成一个MD5码)
*
* @return 唯一id
*/
String getUniqueId();
/**
* 获取图片地址
* @return 图片地址
*/
String getImageUrl();
/**
* 处理图片
* @param bytes 原始图片字节码
* @return 处理后图片
*/
Bitmap onPreHandle( byte[] bytes);
/**
* 图片加载成功回调
* @param bitmap 最终图片
* @param url 图片地址
*/
void onImageLoadSuccess( Bitmap bitmap, String url);
/**
* 图片加载成功回调
* @param url 图片地址
*/
void onImageLoadFailed( String url);
}
BitmapHandle类(位图处理策略)
实现图片处理策略的所有接口,在onPreHandle方法中,通过byte[](图片字节数组)对图片进行压缩处理。在getUniqueId方法中,返回一个唯一Id。由于位图处理策略中,图片压缩处理只与ImageUrl有关,所以通过EncryptionUtil.getMd5("BitmapHandle" + mUrl)获取唯一Id。注意,此唯一Id将用在LruChache内存缓存中,因此必须唯一。
public
class
BitmapHandle
implements
IImageHandle {
public interface BitmapHandleListener {
void onHandle( Bitmap bitmap);
}
private BitmapHandleListener mListener;
private String mUrl;
public BitmapHandle( String url, BitmapHandleListener listener){
mListener = listener;
mUrl = url;
}
@Override
public String getUniqueId(){
return EncryptionUtil .getMd5( "BitmapHandle" + mUrl);
}
@Override
public String getImageUrl(){
return mUrl;
}
@Override
public Bitmap onPreHandle( byte[] bytes){
BitmapFactory . Options options = new BitmapFactory. Options();
options .inJustDecodeBounds = true;
BitmapFactory .decodeByteArray(bytes, 0, bytes .length, options);
//根据不同的图片格式,选择不同的像素格式,减小内存占用。
if (options .outMimeType != null && options .outMimeType .equals( "image/jpeg")){
options .inPreferredConfig = Bitmap . Config .RGB_565;
} else if (options .outMimeType != null && options .outMimeType .equals( "image/png")){
options .inPreferredConfig = Bitmap . Config .ARGB_8888;
}
options .inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory .decodeByteArray(bytes, 0, bytes .length, options);
return bitmap;
}
@Override
public void onImageLoadSuccess( Bitmap bitmap, String url){
if (mListener != null){
mListener .onHandle(bitmap);
}
}
@Override
public void onImageLoadFailed( String url){
if (mListener != null){
mListener .onHandle( ResourceUtil .getBitmap( R .drawable .ic_no_picture));
}
}
}
public interface BitmapHandleListener {
void onHandle( Bitmap bitmap);
}
private BitmapHandleListener mListener;
private String mUrl;
public BitmapHandle( String url, BitmapHandleListener listener){
mListener = listener;
mUrl = url;
}
@Override
public String getUniqueId(){
return EncryptionUtil .getMd5( "BitmapHandle" + mUrl);
}
@Override
public String getImageUrl(){
return mUrl;
}
@Override
public Bitmap onPreHandle( byte[] bytes){
BitmapFactory . Options options = new BitmapFactory. Options();
options .inJustDecodeBounds = true;
BitmapFactory .decodeByteArray(bytes, 0, bytes .length, options);
//根据不同的图片格式,选择不同的像素格式,减小内存占用。
if (options .outMimeType != null && options .outMimeType .equals( "image/jpeg")){
options .inPreferredConfig = Bitmap . Config .RGB_565;
} else if (options .outMimeType != null && options .outMimeType .equals( "image/png")){
options .inPreferredConfig = Bitmap . Config .ARGB_8888;
}
options .inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory .decodeByteArray(bytes, 0, bytes .length, options);
return bitmap;
}
@Override
public void onImageLoadSuccess( Bitmap bitmap, String url){
if (mListener != null){
mListener .onHandle(bitmap);
}
}
@Override
public void onImageLoadFailed( String url){
if (mListener != null){
mListener .onHandle( ResourceUtil .getBitmap( R .drawable .ic_no_picture));
}
}
}
ImageLoader类(图片加载外观类)
在ImageLoader中,封装了以上的内部实现。以BitmapHandler为例,其封装如下:
/*********************** 位图处理策略 ***********************/
public void getBitmap( String url, BitmapHandle . BitmapHandleListener listener) {
mLoadCenter .submitTask( new BitmapHandle(url, listener));
}
public void getBitmap( String url, BitmapHandle . BitmapHandleListener listener) {
mLoadCenter .submitTask( new BitmapHandle(url, listener));
}
代码地址
/************************** 项目介绍 *****************************/
此项目为本人知识库,里面保存了许多自己实现的控件和功能,其中包括Volley使用介绍,视图注入框架,EventBus框架,还有图片加载框架等...
查看ImageLoader使用效果方法:运行项目,点击顶部搜索框,键入“imageloader”,即可快速搜索到ImageLoader使用知识点。
如果觉得好,不要忘记动动手指,点点star!