图片缓存

如果每次加载同一张图片都要从网络获取,那代价实在太大了。所以同一张图片只要从网络获取一次就够了,然后在本地缓存起来,之后加载同一张图片时就从缓存中加载就可以了。从内存缓存读取图片是最快的,但是因为内存容量有限,所以最好再加上文件缓存。文件缓存空间也不是无限大的,容量越大读取效率越低,因此可以设置一个限定大小比如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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Verilog是一种硬件描述语言,用于设计和描述数字电路。图片缓存通常是在图形处理单元(GPU)中使用的一种技术,用于临时存储图像数据以提高图像处理效率。在Verilog中实现图片缓存涉及到处理图像数据的存储、读取和处理等方面。 在Verilog中,可以使用多种方式来实现图片缓存。一种常见的方式是使用双端口的RAM(Random Access Memory)来存储图像数据。其中一个端口用于写入图像数据,另一个端口用于读取图像数据。这样可以实现并行地读取和写入图像数据,提高数据访问的效率。 以下是一个简单示例,演示如何使用Verilog实现一个基本的图片缓存: ```verilog module ImageCache ( input wire [7:0] image_data, input wire write_enable, input wire read_enable, input wire [7:0] read_address, output wire [7:0] read_data ); reg [7:0] cache [0:255]; always @(posedge clk) begin if (write_enable) begin cache[read_address] <= image_data; end end always @(posedge clk) begin if (read_enable) begin read_data <= cache[read_address]; end end endmodule ``` 上述代码定义了一个名为ImageCache的模块,其中包含一个8位宽的图像数据输入端口(image_data)、一个写使能端口(write_enable)、一个读使能端口(read_enable)、一个8位宽的读地址端口(read_address)和一个8位宽的读数据输出端口(read_data)。 在模块内部,使用了一个由256个8位宽寄存器(cache)组成的数组来实现图片缓存。在上升沿时钟触发的always块中,根据写使能信号,将图像数据写入到指定的缓存地址中;在下降沿时钟触发的always块中,根据读使能信号和读地址,从指定的缓存地址读取图像数据并输出到读数据端口。 需要注意的是,上述示例只是一个简单的图片缓存实现,实际应用中可能需要考虑更多的功能和细节,例如数据读写的时序、地址映射算法、缓存策略等。具体的实现方式和细节可以根据具体需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值