android+缓存管理,Android图片管理组件(双缓存+异步加载)

本文介绍了一个名为ImageManager2的Android图片加载类,它利用LruCache进行内存缓存,同时结合DiskLruCache实现磁盘持久化,提供网络请求管理和缓存策略,确保在有限内存下优化图片加载性能。
摘要由CSDN通过智能技术生成

package com.example.util;

import java.io.File;

import java.util.Iterator;

import java.util.LinkedList;

import java.util.Queue;

import java.util.Stack;

import org.apache.http.HttpEntity;

import org.apache.http.HttpResponse;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.util.EntityUtils;

import android.app.ActivityManager;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.drawable.BitmapDrawable;

import android.graphics.drawable.ColorDrawable;

import android.graphics.drawable.Drawable;

import android.graphics.drawable.TransitionDrawable;

import android.media.ThumbnailUtils;

import android.os.Handler;

import android.os.HandlerThread;

import android.os.Looper;

import android.os.Message;

import android.support.v4.util.LruCache;

import android.widget.ImageView;

import com.example.MyApplication;

/**

* 图片加载类

*

* @author 月月鸟

*/

public class ImageManager2 {

private static ImageManager2 imageManager;

public LruCache mMemoryCache;

private static final int DISK_CACHE_SIZE =1024 *1024 *20;// 10MB

private static final String DISK_CACHE_SUBDIR ="thumbnails";

public DiskLruCache mDiskCache;

private static MyApplication myapp;

/** 图片加载队列,后进先出 */

private Stack mImageQueue =new Stack();

/** 图片请求队列,先进先出,用于存放已发送的请求。 */

private Queue mRequestQueue =new LinkedList();

/** 图片加载线程消息处理器 */

private Handler mImageLoaderHandler;

/** 图片加载线程是否就绪 */

private boolean mImageLoaderIdle =true;

/** 请求图片 */

private static final int MSG_REQUEST =1;

/** 图片加载完成 */

private static final int MSG_REPLY =2;

/** 中止图片加载线程 */

private static final int MSG_STOP =3;

/** 如果图片是从网络加载,则应用渐显动画,如果从缓存读出则不应用动画 */

private boolean isFromNet =true;

/**

* 获取单例,只能在UI线程中使用。

*

* @param context

* @return

*/

public static ImageManager2 from(Context context) {

// 如果不在ui线程中,则抛出异常

if (Looper.myLooper() != Looper.getMainLooper()) {

throw new RuntimeException("Cannot instantiate outside UI thread.");

}

if (myapp ==null) {

myapp = (MyApplication) context.getApplicationContext();

}

if (imageManager ==null) {

imageManager =new ImageManager2(myapp);

}

return imageManager;

}

/**

* 私有构造函数,保证单例模式

*

* @param context

*/

private ImageManager2(Context context) {

int memClass = ((ActivityManager) context

.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();

memClass = memClass >32 ?32 : memClass;

// 使用可用内存的1/8作为图片缓存

final int cacheSize =1024 *1024 * memClass /8;

mMemoryCache =new LruCache(cacheSize) {

protected int sizeOf(String key, Bitmap bitmap) {

return bitmap.getRowBytes() * bitmap.getHeight();

}

};

File cacheDir = DiskLruCache

.getDiskCacheDir(context, DISK_CACHE_SUBDIR);

mDiskCache = DiskLruCache.openCache(context, cacheDir, DISK_CACHE_SIZE);

}

/**

* 存放图片信息

*/

class ImageRef {

/** 图片对应ImageView控件 */

ImageView imageView;

/** 图片URL地址 */

String url;

/** 图片缓存路径 */

String filePath;

/** 默认图资源ID */

int resId;

int width =0;

int height =0;

/**

* 构造函数

*

* @param imageView

* @param url

* @param resId

* @param filePath

*/

ImageRef(ImageView imageView, String url, String filePath,int resId) {

this.imageView = imageView;

this.url = url;

this.filePath = filePath;

this.resId = resId;

}

ImageRef(ImageView imageView, String url, String filePath,int resId,

int width,int height) {

this.imageView = imageView;

this.url = url;

this.filePath = filePath;

this.resId = resId;

this.width = width;

this.height = height;

}

}

/**

* 显示图片

*

* @param imageView

* @param url

* @param resId

*/

public void displayImage(ImageView imageView, String url,int resId) {

if (imageView ==null) {

return;

}

if (imageView.getTag() !=null

&& imageView.getTag().toString().equals(url)) {

return;

}

if (resId >=0) {

if (imageView.getBackground() ==null) {

imageView.setBackgroundResource(resId);

}

imageView.setImageDrawable(null);

}

if (url ==null || url.equals("")) {

return;

}

// 添加url tag

imageView.setTag(url);

// 读取map缓存

Bitmap bitmap = mMemoryCache.get(url);

if (bitmap !=null) {

setImageBitmap(imageView, bitmap,false);

return;

}

// 生成文件名

String filePath = urlToFilePath(url);

if (filePath ==null) {

return;

}

queueImage(new ImageRef(imageView, url, filePath, resId));

}

/**

* 显示图片固定大小图片的缩略图,一般用于显示列表的图片,可以大大减小内存使用

*

* @param imageView 加载图片的控件

* @param url 加载地址

* @param resId 默认图片

* @param width 指定宽度

* @param height 指定高度

*/

public void displayImage(ImageView imageView, String url,int resId,

int width,int height) {

if (imageView ==null) {

return;

}

if (resId >=0) {

if (imageView.getBackground() ==null) {

imageView.setBackgroundResource(resId);

}

imageView.setImageDrawable(null);

}

if (url ==null || url.equals("")) {

return;

}

// 添加url tag

imageView.setTag(url);

// 读取map缓存

Bitmap bitmap = mMemoryCache.get(url + width + height);

if (bitmap !=null) {

setImageBitmap(imageView, bitmap,false);

return;

}

// 生成文件名

String filePath = urlToFilePath(url);

if (filePath ==null) {

return;

}

queueImage(new ImageRef(imageView, url, filePath, resId, width, height));

}

/**

* 入队,后进先出

*

* @param imageRef

*/

public void queueImage(ImageRef imageRef) {

// 删除已有ImageView

Iterator iterator = mImageQueue.iterator();

while (iterator.hasNext()) {

if (iterator.next().imageView == imageRef.imageView) {

iterator.remove();

}

}

// 添加请求

mImageQueue.push(imageRef);

sendRequest();

}

/**

* 发送请求

*/

private void sendRequest() {

// 开启图片加载线程

if (mImageLoaderHandler ==null) {

HandlerThread imageLoader =new HandlerThread("image_loader");

imageLoader.start();

mImageLoaderHandler =new ImageLoaderHandler(

imageLoader.getLooper());

}

// 发送请求

if (mImageLoaderIdle && mImageQueue.size() >0) {

ImageRef imageRef = mImageQueue.pop();

Message message = mImageLoaderHandler.obtainMessage(MSG_REQUEST,

imageRef);

mImageLoaderHandler.sendMessage(message);

mImageLoaderIdle =false;

mRequestQueue.add(imageRef);

}

}

/**

* 图片加载线程

*/

class ImageLoaderHandlerextends Handler {

public ImageLoaderHandler(Looper looper) {

super(looper);

}

public void handleMessage(Message msg) {

if (msg ==null)

return;

switch (msg.what) {

case MSG_REQUEST:// 收到请求

Bitmap bitmap =null;

Bitmap tBitmap =null;

if (msg.obj !=null && msg.objinstanceof ImageRef) {

ImageRef imageRef = (ImageRef) msg.obj;

String url = imageRef.url;

if (url ==null)

return;

// 如果本地url即读取sd相册图片,则直接读取,不用经过DiskCache

if (url.toLowerCase().contains("dcim")) {

tBitmap =null;

BitmapFactory.Options opt =new BitmapFactory.Options();

opt.inSampleSize =1;

opt.inJustDecodeBounds =true;

BitmapFactory.decodeFile(url, opt);

int bitmapSize = opt.outHeight * opt.outWidth *4;

opt.inSampleSize = bitmapSize / (1000 *2000);

opt.inJustDecodeBounds =false;

tBitmap = BitmapFactory.decodeFile(url, opt);

if (imageRef.width !=0 && imageRef.height !=0) {

bitmap = ThumbnailUtils.extractThumbnail(tBitmap,

imageRef.width, imageRef.height,

ThumbnailUtils.OPTIONS_RECYCLE_INPUT);

isFromNet =true;

}else {

bitmap = tBitmap;

tBitmap =null;

}

}else

bitmap = mDiskCache.get(url);

if (bitmap !=null) {

// ToolUtil.log("从disk缓存读取");

// 写入map缓存

if (imageRef.width !=0 && imageRef.height !=0) {

if (mMemoryCache.get(url + imageRef.width

+ imageRef.height) ==null)

mMemoryCache.put(url + imageRef.width

+ imageRef.height, bitmap);

}else {

if (mMemoryCache.get(url) ==null)

mMemoryCache.put(url, bitmap);

}

}else {

try {

byte[] data = loadByteArrayFromNetwork(url);

if (data !=null) {

BitmapFactory.Options opt =new BitmapFactory.Options();

opt.inSampleSize =1;

opt.inJustDecodeBounds =true;

BitmapFactory.decodeByteArray(data,0,

data.length, opt);

int bitmapSize = opt.outHeight * opt.outWidth

*4;// pixels*3 if it's RGB and pixels*4

// if it's ARGB

if (bitmapSize >1000 *1200)

opt.inSampleSize =2;

opt.inJustDecodeBounds =false;

tBitmap = BitmapFactory.decodeByteArray(data,

0, data.length, opt);

if (imageRef.width !=0 && imageRef.height !=0) {

bitmap = ThumbnailUtils

.extractThumbnail(

tBitmap,

imageRef.width,

imageRef.height,

ThumbnailUtils.OPTIONS_RECYCLE_INPUT);

}else {

bitmap = tBitmap;

tBitmap =null;

}

if (bitmap !=null && url !=null) {

// 写入SD卡

if (imageRef.width !=0

&& imageRef.height !=0) {

mDiskCache.put(url + imageRef.width

+ imageRef.height, bitmap);

mMemoryCache.put(url + imageRef.width

+ imageRef.height, bitmap);

}else {

mDiskCache.put(url, bitmap);

mMemoryCache.put(url, bitmap);

}

isFromNet =true;

}

}

}catch (OutOfMemoryError e) {

}

}

}

if (mImageManagerHandler !=null) {

Message message = mImageManagerHandler.obtainMessage(

MSG_REPLY, bitmap);

mImageManagerHandler.sendMessage(message);

}

break;

case MSG_STOP:// 收到终止指令

Looper.myLooper().quit();

break;

}

}

}

/** UI线程消息处理器 */

private Handler mImageManagerHandler =new Handler() {

@Override

public void handleMessage(Message msg) {

if (msg !=null) {

switch (msg.what) {

case MSG_REPLY:// 收到应答

do {

ImageRef imageRef = mRequestQueue.remove();

if (imageRef ==null)

break;

if (imageRef.imageView ==null

|| imageRef.imageView.getTag() ==null

|| imageRef.url ==null)

break;

if (!(msg.objinstanceof Bitmap) || msg.obj ==null) {

break;

}

Bitmap bitmap = (Bitmap) msg.obj;

// 非同一ImageView

if (!(imageRef.url).equals((String) imageRef.imageView

.getTag())) {

break;

}

setImageBitmap(imageRef.imageView, bitmap, isFromNet);

isFromNet =false;

}while (false);

break;

}

}

// 设置闲置标志

mImageLoaderIdle =true;

// 若服务未关闭,则发送下一个请求。

if (mImageLoaderHandler !=null) {

sendRequest();

}

}

};

/**

* 添加图片显示渐现动画

*

*/

private void setImageBitmap(ImageView imageView, Bitmap bitmap,

boolean isTran) {

if (isTran) {

final TransitionDrawable td =new TransitionDrawable(

new Drawable[] {

new ColorDrawable(android.R.color.transparent),

new BitmapDrawable(bitmap) });

td.setCrossFadeEnabled(true);

imageView.setImageDrawable(td);

td.startTransition(300);

}else {

imageView.setImageBitmap(bitmap);

}

}

/**

* 从网络获取图片字节数组

*

* @param url

* @return

*/

private byte[] loadByteArrayFromNetwork(String url) {

try {

HttpGet method =new HttpGet(url);

HttpResponse response = myapp.getHttpClient().execute(method);

HttpEntity entity = response.getEntity();

return EntityUtils.toByteArray(entity);

}catch (Exception e) {

return null;

}

}

/**

* 根据url生成缓存文件完整路径名

*

* @param url

* @return

*/

public String urlToFilePath(String url) {

// 扩展名位置

int index = url.lastIndexOf('.');

if (index == -1) {

return null;

}

StringBuilder filePath =new StringBuilder();

// 图片存取路径

filePath.append(myapp.getCacheDir().toString()).append('/');

// 图片文件名

filePath.append(MD5.Md5(url)).append(url.substring(index));

return filePath.toString();

}

/**

* Activity#onStop后,ListView不会有残余请求。

*/

public void stop() {

// 清空请求队列

mImageQueue.clear();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值