文档章节

Android网络图片缓存

 等待流星
发布于 2014/04/24 13:40
字数 1234
阅读 945
收藏 1

获取一张图片,从三个地方进行获取,首先是内存缓存,然后是文件缓存,最后才从网络中获取。

//内存缓存

public class ImageMemoryCache {

/**

* 从内存读取数据速度是最快的,为了更大限度使用内存,这里使用了两层缓存。 硬引用缓存不会轻易被回收,用来保存常用数据,不常用的转入软引用缓存。

*/

private static final int SOFT_CACHE_SIZE = 15; // 软引用缓存容量

private static LruCache<String, Bitmap> mLruCache; // 硬引用缓存

private static LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache; // 软引用缓存


public ImageMemoryCache(Context context) {

int memClass = ((ActivityManager) context

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

int cacheSize = 1024 * 1024 * memClass / 4; // 硬引用缓存容量,为系统可用内存的1/4

mLruCache = new LruCache<String, Bitmap>(cacheSize) {

@Override

protected int sizeOf(String key, Bitmap value) {

if (value != null)

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

else

return 0;

}


@Override

protected void entryRemoved(boolean evicted, String key,

Bitmap oldValue, Bitmap newValue) {

if (oldValue != null)

// 硬引用缓存容量满的时候,会根据LRU算法把最近没有被使用的图片转入此软引用缓存

mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));

}

};

mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(

SOFT_CACHE_SIZE, 0.75f, true) {

private static final long serialVersionUID = 6040103833179403725L;


@Override

protected boolean removeEldestEntry(

Entry<String, SoftReference<Bitmap>> eldest) {

if (size() > SOFT_CACHE_SIZE) {

return true;

}

return false;

}

};

}


/**

* 从缓存中获取图片

*/

public Bitmap getBitmapFromCache(String url) {

Bitmap bitmap;

// 先从硬引用缓存中获取

synchronized (mLruCache) {

bitmap = mLruCache.get(url);

if (bitmap != null) {

// 如果找到的话,把元素移到LinkedHashMap的最前面,从而保证在LRU算法中是最后被删除

mLruCache.remove(url);

mLruCache.put(url, bitmap);

return bitmap;

}

}

// 如果硬引用缓存中找不到,到软引用缓存中找

synchronized (mSoftCache) {

SoftReference<Bitmap> bitmapReference = mSoftCache.get(url);

if (bitmapReference != null) {

bitmap = bitmapReference.get();

if (bitmap != null) {

// 将图片移回硬缓存

mLruCache.put(url, bitmap);

mSoftCache.remove(url);

return bitmap;

} else {

mSoftCache.remove(url);

}

}

}

return null;

}


/**

* 添加图片到缓存

*/

public void addBitmapToCache(String url, Bitmap bitmap) {

if (bitmap != null) {

synchronized (mLruCache) {

mLruCache.put(url, bitmap);

}

}

}


public void clearCache() {

mSoftCache.clear();

}

}



//文件缓存,缓存到SD卡上

public class ImageFileCache {

private static final String CACHDIR = "ImgCach";

private static final String WHOLESALE_CONV = ".cach";

private static final int MB = 1024*1024;

   private static final int CACHE_SIZE = 10;

   private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;

public ImageFileCache() {

//清理文件缓存

removeCache(getDirectory());

}

   /** 从缓存中获取图片 **/

public Bitmap getImage(final String url) {

final String path = getDirectory() + "/" + convertUrlToFileName(url);

File file = new File(path);

if (file.exists()) {

Bitmap bmp = BitmapFactory.decodeFile(path);

if (bmp == null) {

file.delete();

} else {

updateFileTime(path);

return bmp;

}

}

return null;

}

   /** 将图片存入文件缓存 **/

public void saveBitmap(Bitmap bm, String url) {

if (bm == null) {

return;

}

       //判断sdcard上的空间

if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {

//SD空间不足

return;

}

String filename = convertUrlToFileName(url);

String dir = getDirectory();

File dirFile = new File(dir);

if (!dirFile.exists())

dirFile.mkdirs();

File file = new File(dir +"/" + filename);

try {

file.createNewFile();

OutputStream outStream = new FileOutputStream(file);

bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);

outStream.flush();

outStream.close();

} catch (FileNotFoundException e) {

           Log.w("ImageFileCache", "FileNotFoundException");

} catch (IOException e) {

           Log.w("ImageFileCache", "IOException");

}

}

/**

* 计算存储目录下的文件大小,

* 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定

* 那么删除40%最近没有被使用的文件

*/

private boolean removeCache(String dirPath) {

File dir = new File(dirPath);

File[] files = dir.listFiles();

if (files == null) {

return true;

}

if (!android.os.Environment.getExternalStorageState().equals(

android.os.Environment.MEDIA_MOUNTED)) {

return false;

}

int dirSize = 0;

for (int i = 0; i < files.length; i++) {

if (files[i].getName().contains(WHOLESALE_CONV)) {

dirSize += files[i].length();

}

}

if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {

int removeFactor = (int) ((0.4 * files.length) + 1);

Arrays.sort(files, new FileLastModifSort());

for (int i = 0; i < removeFactor; i++) {

if (files[i].getName().contains(WHOLESALE_CONV)) {

files[i].delete();

}

}

}

if (freeSpaceOnSd() <= CACHE_SIZE) {

return false;

}

return true;

}

   /** 修改文件的最后修改时间 **/

public void updateFileTime(String path) {

File file = new File(path);

long newModifiedTime = System.currentTimeMillis();

file.setLastModified(newModifiedTime);

}

   /** 计算sdcard上的剩余空间 **/

private int freeSpaceOnSd() {

StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());

double sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;

return (int) sdFreeMB;

}

   /** 将url转成文件名 **/

private String convertUrlToFileName(String url) {

String[] strs = url.split("/");

return strs[strs.length - 1] + WHOLESALE_CONV;

}

   /** 获得缓存目录 **/

private String getDirectory() {

String dir = getSDPath() + "/" + CACHDIR;

return dir;

}

   /** 取SD卡路径 **/

private String getSDPath() {

File sdDir = null;

boolean sdCardExist = Environment.getExternalStorageState().equals(

android.os.Environment.MEDIA_MOUNTED);  //判断sd卡是否存在

if (sdCardExist) {

sdDir = Environment.getExternalStorageDirectory();  //获取根目录

}

if (sdDir != null) {

return sdDir.toString();

} else {

return "";

}

}

/**

* 根据文件的最后修改时间进行排序

*/

private class FileLastModifSort implements Comparator<File> {

public int compare(File arg0, File arg1) {

if (arg0.lastModified() > arg1.lastModified()) {

return 1;

} else if (arg0.lastModified() == arg1.lastModified()) {

return 0;

} else {

return -1;

}

}

}

}



//从网络加载图片

public class ImageGetFromHttp {

private static final String LOG_TAG = "ImageGetFromHttp";

public static Bitmap downloadBitmap(String url) {

final HttpClient client = new DefaultHttpClient();

final HttpGet getRequest = new HttpGet(url);

try {

HttpResponse response = client.execute(getRequest);

final int statusCode = response.getStatusLine().getStatusCode();

if (statusCode != HttpStatus.SC_OK) {

Log.w(LOG_TAG, "Error " + statusCode + " while retrieving bitmap from " + url);

return null;

}

final HttpEntity entity = response.getEntity();

if (entity != null) {

InputStream inputStream = null;

try {

inputStream = entity.getContent();

FilterInputStream fit = new FlushedInputStream(inputStream);

return BitmapFactory.decodeStream(fit);

} finally {

if (inputStream != null) {

inputStream.close();

inputStream = null;

}

entity.consumeContent();

}

}

} catch (IOException e) {

getRequest.abort();

           Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);

} catch (IllegalStateException e) {

getRequest.abort();

Log.w(LOG_TAG, "Incorrect URL: " + url);

} catch (Exception e) {

getRequest.abort();

           Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);

} finally {

client.getConnectionManager().shutdown();

}

return null;

}

/*

* An InputStream that skips the exact number of bytes provided, unless it reaches EOF.

*/

static class FlushedInputStream extends FilterInputStream {

public FlushedInputStream(InputStream inputStream) {

super(inputStream);

}

       @Override

public long skip(long n) throws IOException {

long totalBytesSkipped = 0L;

while (totalBytesSkipped < n) {

long bytesSkipped = in.skip(n - totalBytesSkipped);

if (bytesSkipped == 0L) {

int b = read();

if (b < 0) {

break;  // we reached EOF

} else {

bytesSkipped = 1; // we read one byte

}

}

totalBytesSkipped += bytesSkipped;

}

return totalBytesSkipped;

}

}

}



//=============================获取图片========================================

/*** 获得一张图片,从三个地方获取,首先是内存缓存,然后是文件缓存,最后从网络获取 ***/

public Bitmap getBitmap(String url) {

// 从内存缓存中获取图片

Bitmap result = memoryCache.getBitmapFromCache(url);

if (result == null) {

// 文件缓存中获取

result = fileCache.getImage(url);

if (result == null) {

// 从网络获取

result = ImageGetFromHttp.downloadBitmap(url);

if (result != null) {

fileCache.saveBitmap(result, url);

memoryCache.addBitmapToCache(url, result);

}

} else {

// 添加到内存缓存

memoryCache.addBitmapToCache(url, result);

}

}

return result;

}


本文转载自:http://blog.163.com/ppy2790@126/blog/static/1032422412013112374922801/

共有 人打赏支持
粉丝 5
博文 78
码字总数 10995
作品 0
崇明
私信 提问
六款值得推荐的android(安卓)开源框架简介【转】

1、volley 项目地址 https://github.com/smanikandan14/Volley-demo (1) JSON,图像等的异步下载; (2) 网络请求的排序(scheduling) (3) 网络请求的优先级处理 (4) 缓存 (5) 多级别取消请求...

hkstar35
2014/07/11
0
0
六款值得推荐的android(安卓)开源框架简介【转】

1、volley 项目地址 https://github.com/smanikandan14/Volley-demo (1) JSON,图像等的异步下载; (2) 网络请求的排序(scheduling) (3) 网络请求的优先级处理 (4) 缓存 (5) 多级别取消请求...

火蚁
2014/07/09
0
1
总结的一些android公共库

最新最准确内容建议直接访问原文:Android公共库(缓存 下拉ListView 下载管理Pro 静默安装 root运行 Java公共类) 介绍总结的一些android公共库,包含缓存(图片缓存、预取缓存)、公共View(下拉...

Trinea
2012/07/16
0
1
【转】值得推荐的android开发框架简介

第一个:Afinal 项目地址:https://github.com/yangfuhai/afinal 功能:一个android的ioc,orm框架,内置了四大模块功 能:FinalAcitivity,FinalBitmap,FinalDb,FinalHttp。通过finalActivi...

kymjs张涛
2014/08/05
0
0
Android的快速开发框架,Afinal 0.2.1 发布

Afinal 是一个android的 orm 和 ioc 框架。而且封装了android中的httpClient,使其更加简单易用。使用finalBitmap,无需考虑bitmap在android中加载的时候oom的问题和快速滑动的时候图片加载位...

xiahuawuyu
2012/11/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spirng事务简单入门

一、概述 spring支持编程式事务管理和声明式事务管理两种方式: 1.编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使...

嘴角轻扬30
12分钟前
2
0
独立IP被恶意绑定域名处理办法

80端口: listen 80 default_server; server_name _; return 444; 443端口: listen 443 ssl default_server; server_name _; 加上证书路径 return 444;...

会当凌绝顶
15分钟前
3
0
RabbitMQ+PHP 教程五(Topics)

开始 在前面的教程中,我们改进了日志系统。我们使用的是一种直接广播方式,而不是只使用一种直接(direct)广播方式的fanout交换机,从而获得了有选择地接收日志的可能性。 虽然使用直接direc...

hansonwong
23分钟前
1
0
未来Linux Kernel 将不支持可变长数组VLA

但使用 VLA 会存在问题,包括增加运行时开销——因为数组长度需要在运行时确定; LLVM Clang 编译器不支持结构内 VLA,它只支持 C99 风格的 VLA;存在安全隐患。Linus Torvalds 对 VLA 的使用...

linux-tao
25分钟前
2
0
给Jenkins增加Linux奴隶节点

Add linux slave node in the Jenkins https://mohitgoyal.co/2017/02/14/add-linux-slave-node-in-the-jenkins/ https://www.howtoforge.com/tutorial/ubuntu-jenkins-master-slave/ https:......

圣洁之子
26分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部