- 浏览: 4170671 次
最新评论
图片缓存
如果每次加载同一张图片都要从网络获取,那代价实在太大了。所以同一张图片只要从网络获取一次就够了,然后在本地缓存起来,之后加载同一张图片时就从缓存中加载就可以了。从内存缓存读取图片是最快的,但是因为内存容量有限,所以最好再加上文件缓存。文件缓存空间也不是无限大的,容量越大读取效率越低,因此可以设置一个限定大小比如10M,或者限定保存时间比如一天。
因此,加载图片的流程应该是:
1、先从内存缓存中获取,取到则返回,取不到则进行下一步;
2、从文件缓存中获取,取到则返回并更新到内存缓存,取不到则进行下一步;
3、从网络下载图片,并更新到内存缓存和文件缓存。
接下来看内存缓存类:ImageMemoryCache
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
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();
}
} |
文件缓存类:ImageFileCache
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
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 ;
}
}
}
} |
从网络获取图片:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
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;
}
}
} |
最后,获取一张图片的流程就如下代码所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/*** 获得一张图片,从三个地方获取,首先是内存缓存,然后是文件缓存,最后从网络获取 ***/ 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;
} |
相关推荐
利用现有的开源的图片缓存框架实现的图片缓存下载,测试程序在TestLoadImage中
完美的网络图片缓存 Android
图片缓存实现例子(ImageCacheDome)图片缓存实现例子(ImageCacheDome)图片缓存实现例子(ImageCacheDome)图片缓存实现例子(ImageCacheDome)图片缓存实现例子(ImageCacheDome)图片缓存实现例子(ImageCacheDome)
Android Google官网的图片缓存源码
listView快速滑动图片缓存实例.欢迎大家下载学习
Android中非常好图片缓存ImageCache,是国外的大牛写的,比较完整系统,但是本人认为也有几个缺点,比如获取磁盘缓存目录的方法,不过,总体非常还是很好的,基本满足各种场景,希望对你有所帮助!
Android图片缓存管理(管理SDK卡例子)。
让你快速构建类似于SDWebImage的图片缓存框架,读者可以直接使用CLWebImage,也可以根据该种思路构建自己的图片缓存处理逻辑,面试或者项目中经常会遇到!实例地址:https://github.com/chengliuAres/CLWebImageDemo
下载下来就能用,,适用于初学图片缓存,,欢迎下载
删除图片缓存文件.bat
实现Android中WebView图片的缓存,并且实现如何替换WebView中默认图片以及如何实现图片的点击。
图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉
一个和图片缓存有关的小项目,就可以当作学习资料来是使用,在学习一下android图pain缓存的原理
图片缓存技术知识点,以及跳转到QQ的代码,本人认为对新手小白还是可以的
react_native图片缓存2.pdf
Android应用源码之listview获取网络图片缓存优化_网络
图片缓存框架
自做asp图片管理系统类,似网易图片浏览页面ajax+image无刷新图片缓存预加载可以键盘操作浏览,附加数据库,安装persits.jpeg组件。用户名admin密码admin
listview获取网络图片缓存优化.zip,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
实现android离线下载功能,滑动切换,图片缓存,滑动切换图片,可用于版本更新开发功能等等。很给力,需要导入2个包。