Android 图片三级缓存


Android开发中,我们经常会使用到网络图片资源,而为了避免频繁的访问网络获取图片资源,我们一般会将网络图片缓存到本地或者内存中以方便使用,这就需要使用到图片的三级缓存:

  1. 通过内存中获得图片
  2. 通过本地sd卡中获得图片
  3. 通过网络请求获得图片
通过使用"内存-本地文件-网络"这样的三级缓存策略,可以大大提高图片展示的效率,同时可以有效的避免图片oom异常的发生。

1. LruCache介绍

LruCache通过使用最近最少使用算法来维护内存缓存中缓存图片的数量,如果缓存达到指定的大小,LruCahe会自动将最近最少使用的图片移除缓存,把最新使用的图片加载内存中,这样可以始终让缓存中的图片维持在一定的数量上,同时可以避免oom异常的产生。在项目中我们只需要创建一个类继承自LruCache就可以实现缓存了。 代码如下:
[java]view plaincopy print?
  1. /**
  2. *继承LruCache实现图片缓存
  3. *
  4. *@authorAdministrator
  5. *
  6. */
  7. classBitmapCacheextendsLruCache<String,Bitmap>{
  8. publicBitmapCache(intmaxSize){
  9. super(maxSize);
  10. }
  11. /**
  12. *返回图片的大小
  13. */
  14. @Override
  15. protectedintsizeOf(Stringkey,Bitmapvalue){
  16. returnvalue.getByteCount();
  17. }
  18. }
  19. /**
  20. *私有构造函数
  21. */
  22. privateImageCacheUtils(Contextcontext){
  23. mContext=context;
  24. //初始化bitmapCache,获得系统可用的最大内存,并将可用内存的1/16作为图片缓存的大小,
  25. intmaxMemory=(int)Runtime.getRuntime().maxMemory();
  26. intmaxSize=maxMemory/16;
  27. mBitmapCache=newBitmapCache(maxSize);
  28. }


2. 三级缓存的实现

代码如下:
[java]view plaincopy print?
  1. packagecom.zk.imagecache;
  2. importjava.io.File;
  3. importjava.io.FileInputStream;
  4. importjava.io.FileOutputStream;
  5. importjava.io.InputStream;
  6. importjava.net.HttpURLConnection;
  7. importjava.net.URL;
  8. importjava.util.concurrent.Callable;
  9. importjava.util.concurrent.ExecutorService;
  10. importjava.util.concurrent.Executors;
  11. importjava.util.concurrent.Future;
  12. importorg.apache.http.HttpResponse;
  13. importorg.apache.http.client.HttpClient;
  14. importorg.apache.http.client.methods.HttpGet;
  15. importorg.apache.http.impl.client.DefaultHttpClient;
  16. importandroid.content.Context;
  17. importandroid.graphics.Bitmap;
  18. importandroid.graphics.Bitmap.CompressFormat;
  19. importandroid.graphics.BitmapFactory;
  20. importandroid.os.AsyncTask;
  21. importandroid.os.Environment;
  22. importandroid.support.v4.util.LruCache;
  23. /**
  24. *图片三级缓存实现1、从内存中获得2、从本地sd卡中获得3、从网络中获得
  25. *
  26. *@authorAdministrator
  27. *
  28. */
  29. publicclassImageCacheUtils{
  30. /**
  31. *上下文
  32. */
  33. privatestaticContextmContext;
  34. /**
  35. *单例
  36. */
  37. privatestaticImageCacheUtilsmImageCacheUtils;
  38. /**
  39. *缓存bitmap
  40. */
  41. privatestaticBitmapCachemBitmapCache;
  42. /**
  43. *私有构造函数
  44. */
  45. privateImageCacheUtils(Contextcontext){
  46. mContext=context;
  47. //初始化bitmapCache,获得系统可用的最大内存,并将可用内存的1/16作为图片缓存的大小,
  48. intmaxMemory=(int)Runtime.getRuntime().maxMemory();
  49. intmaxSize=maxMemory/16;
  50. mBitmapCache=newBitmapCache(maxSize);
  51. }
  52. /**
  53. *获得图片缓存对象
  54. *
  55. *@paramcontext
  56. *@return
  57. */
  58. publicstaticImageCacheUtilsgetInstance(Contextcontext){
  59. if(mImageCacheUtils==null){
  60. mImageCacheUtils=newImageCacheUtils(context);
  61. }
  62. returnmImageCacheUtils;
  63. }
  64. /**
  65. *获得Bitmap对象
  66. *
  67. *@paramurl
  68. *@return
  69. */
  70. publicBitmapgetBitmap(Stringurl){
  71. //将url地址的md5加密后的32位字符作为key,保证唯一性
  72. Stringkey=SecurityUtils.MD5.get32MD5String(url);
  73. //1、从内存中获得bitmap
  74. Bitmapbitmap=mBitmapCache.get(key);
  75. if(bitmap!=null){
  76. returnbitmap;
  77. }
  78. //2、内存中不存在该bitmap,从sd卡中获取
  79. bitmap=getDiskBitmap(key);
  80. if(bitmap!=null){
  81. returnbitmap;
  82. }
  83. //3、从网络中获得Bitmap
  84. bitmap=getNetBitmap(url);
  85. if(bitmap!=null){
  86. returnbitmap;
  87. }
  88. returnnull;
  89. }
  90. /**
  91. *将图片保存到内存中
  92. *
  93. *@paramurl
  94. *@parambitmap
  95. */
  96. privatevoidsaveBitmap(Stringkey,Bitmapbitmap){
  97. if(mBitmapCache.get(key)==null){
  98. mBitmapCache.put(key,bitmap);
  99. }
  100. }
  101. /**
  102. *从sd卡中获得图片
  103. *
  104. *@paramkey
  105. *@return
  106. */
  107. privateBitmapgetDiskBitmap(Stringkey){
  108. try{
  109. Filefile=getDiskFile(key);
  110. if(file.exists()){
  111. FileInputStreamfis=newFileInputStream(file);
  112. Bitmapbitmap=BitmapFactory.decodeStream(fis);
  113. //加载到内存中
  114. mBitmapCache.put(key,bitmap);
  115. returnbitmap;
  116. }
  117. }catch(Exceptione){
  118. e.printStackTrace();
  119. returnnull;
  120. }
  121. returnnull;
  122. }
  123. /**
  124. *将图片保存到sd卡中
  125. *
  126. *@paramkey
  127. */
  128. privatevoidsaveDiskBitmap(Stringkey,Bitmapbitmap){
  129. try{
  130. Filefile=getDiskFile(key);
  131. file.createNewFile();
  132. FileOutputStreamfos=newFileOutputStream(file);
  133. Bitmap.createScaledBitmap(bitmap,bitmap.getWidth(),
  134. bitmap.getHeight(),true);
  135. bitmap.compress(CompressFormat.PNG,100,fos);
  136. fos.close();
  137. }catch(Exceptione){
  138. e.printStackTrace();
  139. }
  140. }
  141. /**
  142. *获得sd卡存储图片路径
  143. *
  144. *@paramurl
  145. *@return
  146. */
  147. privateFilegetDiskFile(Stringkey){
  148. Stringpath="";
  149. StringexternalStorageState=Environment.getExternalStorageState();
  150. if(Environment.MEDIA_MOUNTED.equals(externalStorageState)){
  151. path=Environment.getExternalStorageDirectory().getAbsolutePath();
  152. }else{
  153. path=mContext.getCacheDir().getAbsolutePath();
  154. }
  155. //获得图片文件
  156. FiledirFile=newFile(path+"/imagecache");
  157. if(!dirFile.exists()){
  158. dirFile.mkdirs();
  159. }
  160. Filefile=newFile(dirFile,key+".png");
  161. returnfile;
  162. }
  163. /**
  164. *从网络中获得图片
  165. *
  166. *@paramurl
  167. */
  168. privateBitmapgetNetBitmap(Stringurl){
  169. try{
  170. //创建一个线程池
  171. ExecutorServicepool=Executors.newCachedThreadPool();
  172. Future<Bitmap>future=pool.submit(newBitmapCallable(url));
  173. Bitmapbitmap=future.get();
  174. pool.shutdown();
  175. //Bitmapbitmap=newBitmapTask().execute(url).get();
  176. returnbitmap;
  177. }catch(Exceptione){
  178. e.printStackTrace();
  179. }
  180. returnnull;
  181. }
  182. /**
  183. *callable线程
  184. *
  185. *@authorAdministrator
  186. *
  187. */
  188. classBitmapCallableimplementsCallable<Bitmap>{
  189. privateStringpath;
  190. publicBitmapCallable(Stringpath){
  191. this.path=path;
  192. }
  193. @Override
  194. publicBitmapcall()throwsException{
  195. HttpClientclient=newDefaultHttpClient();
  196. HttpGethttpPost=newHttpGet(path);
  197. HttpResponseresponse=client.execute(httpPost);
  198. intstatusCode=response.getStatusLine().getStatusCode();
  199. if(statusCode==200){
  200. InputStreaminputStream=response.getEntity().getContent();
  201. Bitmapbitmap=BitmapFactory.decodeStream(inputStream);
  202. if(bitmap!=null){
  203. Stringkey=SecurityUtils.MD5.get32MD5String(path);
  204. //保存到内存
  205. saveBitmap(key,bitmap);
  206. //保存到sd卡
  207. saveDiskBitmap(key,bitmap);
  208. }
  209. inputStream.close();
  210. returnbitmap;
  211. }
  212. returnnull;
  213. }
  214. }
  215. classBitmapTaskextendsAsyncTask<String,Integer,Bitmap>{
  216. @Override
  217. protectedBitmapdoInBackground(String...params){
  218. try{
  219. Stringpath=params[0];
  220. URLurl=newURL(path);
  221. HttpURLConnectionconn=(HttpURLConnection)url
  222. .openConnection();
  223. conn.setRequestMethod("GET");
  224. conn.setConnectTimeout(5000);
  225. InputStreaminputStream=conn.getInputStream();
  226. Bitmapbitmap=BitmapFactory.decodeStream(inputStream);
  227. if(bitmap!=null){
  228. Stringkey=SecurityUtils.MD5.get32MD5String(path);
  229. //保存到内存
  230. saveBitmap(key,bitmap);
  231. //保存到sd卡
  232. saveDiskBitmap(key,bitmap);
  233. }
  234. inputStream.close();
  235. returnbitmap;
  236. }catch(Exceptione){
  237. e.printStackTrace();
  238. }
  239. returnnull;
  240. }
  241. @Override
  242. protectedvoidonPostExecute(Bitmapresult){
  243. super.onPostExecute(result);
  244. }
  245. }
  246. /**
  247. *继承LruCache实现图片缓存
  248. *
  249. *@authorAdministrator
  250. *
  251. */
  252. classBitmapCacheextendsLruCache<String,Bitmap>{
  253. publicBitmapCache(intmaxSize){
  254. super(maxSize);
  255. }
  256. /**
  257. *返回图片的大小
  258. */
  259. @Override
  260. protectedintsizeOf(Stringkey,Bitmapvalue){
  261. returnvalue.getByteCount();
  262. }
  263. }
  264. }

具体调用:
[java]view plaincopy print?
  1. mBtnShow=(Button)findViewById(R.id.btn_show);
  2. mIvShow=(ImageView)findViewById(R.id.iv_show);
  3. mBtnShow.setOnClickListener(newOnClickListener(){
  4. @Override
  5. publicvoidonClick(Viewv){
  6. mIvShow.setImageBitmap(ImageCacheUtils
  7. .getInstance(MainActivity.this)
  8. .getBitmap(
  9. "http://img.my.csdn.net/uploads/201407/26/1406383213_3557.jpg"));
  10. }
  11. });

效果图: 源码下载

优质内容筛选与推荐>>
1、软件测试 之 白盒测试 掠影
2、vector、list、deque三者比较
3、HTML DOM属性
4、建站参考
5、[Swift]LeetCode633. 平方数之和 | Sum of Square Numbers


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn