Android技术积累:图片缓存管理

【AI学习笔记】Coze平台实现将Excel文档批量导入数据库全过程 通过Coze平台实现将Excel文档批量导入数据库的全流程,包括B站现有参考教程全方位解读、自己实操的一些BUG解决过程,以及一些疑难问题的探索。 阅读详情

http://keegan-lee.diandian.com/post/2012-12-06/40047548955

如果每次加载同一张图片都要从网络获取,那代价实在太大了。所以同一张图片只要从网络获取一次就够了,然后在本地缓存起来,之后加载同一张图片时就从缓存中加载就可以了。从内存缓存读取图片是最快的,但是因为内存容量有限,所以最好再加上文件缓存。文件缓存空间也不是无限大的,容量越大读取效率越低,因此可以设置一个限定大小比如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;
}
微信小程序云开发订单微信支付与小票和标签打印的完整高效流程 本片文章全文12000字,细致讲述从申请账户到小程序注册到打印机的选型最后到实现微信小程序云开发订单支付更新与小票,标签打印完整的高效流程。客户A在我们的点餐平台上点了一杯咖啡,所以客户要在选好后付款,在付款完成后商家的小票打印机和标签打印机打印出本订单的相关信息。 阅读详情

相关推荐

ATGM332D模块串口配置保姆级教程:从9600波特率到NMEA数据过滤,一次搞定

本文提供ATGM332D模块串口配置的详细教程,涵盖从基础硬件连接到高级NMEA数据过滤的全过程。内容包括波特率优化、数据输出频率调整、NMEA语句过滤等实用技巧,帮助开发者快速掌握GNSS模块配置,提升定位系统性能。

weixin_30664051的博客 513

Android如何高效的加载图片(3)--- 图片的缓存

如果我们要不止一次去加载很多的图片,像在ListView、GridView、ViewPager等控件中加载图片。本篇将为大家介绍怎样在在内存和磁盘中缓存图片。内存缓存(Memory Cache)内存缓存可以让我们快速的访问图片,我们通常使用LruCache类来进行内存缓存,它可以将一个最近应用的对象,保存到一个强引用的LinkedHashMap中,并且当内存不够的时候,及时的去释放掉最近使用的对象。

D先生的博客 641

【AI概念】迁移学习 vs. 域自适应 vs. 域泛化|定义、核心原理、数学表达、易混淆点与工程选择建议|实际案例、工程实现细节、未来研究趋势、实际应用场景

大家好,我是爱酱。本篇将会详细梳理迁移学习(Transfer Learning)、域自适应(Domain Adaptation)、域泛化(Domain Generalization)三大常被混淆的核心概念,结合数学公式、典型算法与实际应用场景,帮助你厘清它们的本质区别、联系与工程意义。 注:本文章含大量数学算式、详细例子说明及大量代码演示,大量干货,建议先收藏再慢慢观看理解。新频道发展不易,你们的每个赞、收藏跟转发都是我继续分享的动力!

AI人工智能爱酱~你的AI学习好帮手~ 2467

Android代码最新快速扫描获取手机内图片、视频、音频、文档等文件

LiveData+Flow+ViewModel+协程遍历扫描手机全部文件,超快速获取到你手机里的全部的图片视频等类型文件,其中有没有你没见过的文件呢,看看那些不良APP给你保存了些什么东西吧。

qq_38496491的博客 2447

从零开始,用Cadence Virtuoso手把手仿真一个1.5V LDO(附完整电路与仿真脚本)

本文详细介绍了如何使用Cadence Virtuoso从零开始仿真一个1.5V LDO,包括环境准备、电路导入、Testbench构建、核心仿真类型分析以及高级调试技巧。通过完整的电路与仿真脚本,帮助读者掌握LDO设计与仿真的关键技术,提升电路设计能力。

weixin_31309419的博客 445

ArcGIS山体坡度、坡向分析

本篇文章主要记录自己在对山体坡向及坡度分析中的一些操作。

Belence_zhao的博客 7412

Android:获取指定文件夹内的所有图片

public static String getNumSmallLetter(int size){ StringBuffer buffer = new StringBuffer(); Random random = new Random(); for(int i=0; i<size;i++){ if(random.nextInt(2) % 2 == 0){//字母 buffer.append((c.

chench 1510

IDEA系列(四):IDEA导入Maven工程项目并配置Tomcat启动

本片文章主要介绍如何导入一个存在的maven项目并配置Tomcat启动项目,方便自己使用,也分享出来,希望可以帮助到其他人。

低调D树苗的博客 1243

Android——从相机/相册获取图片

【代码】Android——从相机/相册获取图片。

大风起兮云飞扬 1288

链接文件及功能安全:英飞凌官方文档摘录 - 基于Tasking与AURIX TC3xx MCAL中Link文件解析以及代码变量定位方法详解

Data区域是用来存放带初始化值的全局变量,在link文件中,这个区域有两种类型,预先定义的区域和默认区域。预先定义的Data区域,例如.data.Ifx_Ssw_Tc1和.data.Cpu1_Main.*,在cpu1_main.c中如果定义了一个带初始化值的变量,则它会放在DSRAM1中的.data.Cpu1_Main.*段中。

梦想技术家 539

基于 Qt C++ 开发一套西门子量子测量系统的控制与数据采集平台

sensorIdCombo->addItems({"QTS-100-001 (温度)", "QPG-200-001 (压力)", "QDS-300-001 (位移)"});precisionTable->setHorizontalHeaderLabels({"传感器ID", "类型", "标称精度", "实际精度", "校准状态"});QWidget *dispWidget = createSensorWidget("量子位移", "mm (±1μm)", 50.0, 0.001);// 传感器状态更新。

寒寒豆豆软件公司的博客 253

Android技术积累:图片缓存管理

原创文章,转载请注明:转载自Keegan小钢 url:  http://keeganlee.me/post/android/20121206 微信订阅号:keeganlee_me如果每次加载同一张图片都要从网络获取,那代价实在太大了。所以同一张图片只要从网络获取一次就够了,然后在本地缓存起来,之后加载同一张图片时就从缓存中加载就可以了。从内存缓存读取图片是最快的,但是因为内存容量有限,所以最好再

Xs15073722800的博客 449

98DX3236内核编译过程小结

0.条件(1)Marvell技术支持提供的压缩文件:GNU EABI:arm-mv5sft-linux-gnueabi_SW3.2.tar.bz2.tar.bz2armebv7-marvell-linux-gnueabi-softfp_i686_201201.tar.bz2CPSS代码:Cpss-PP-DxCh-4.2_012.zipLinux内核文件:lsp-4.2_012.zipLSP-Uni...

snaking616 1803
上一篇: HashMap和Hashtable的区别
下一篇: Android Fragments 详细使用
stonenotes123
博客等级 码龄15年 30粉丝 176原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值