图片缓存构架

1、权限

<uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2、视图

1)activity_main.xml

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical"
 6     tools:context=".MainActivity" >
 7
 8     <ListView
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:id="@+id/lv"
12         />
13
14 </LinearLayout>

2)lv_item.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical" >
 6     <ImageView
 7         android:layout_width="wrap_content"
 8         android:layout_height="wrap_content"
 9         android:id="@+id/iv"
10         />
11
12 </LinearLayout>

3、MainActivity类

 1 package com.zyh.zyh_imageloader;
 2
 3 import android.os.Bundle;
 4 import android.app.Activity;
 5 import android.view.Menu;
 6 import android.widget.ListView;
 7
 8 public class MainActivity extends Activity {
 9     private ListView lv;
10     private final String HOST_PATH = "http://192.168.1.100/android/cache_img/thumb/";
11     private String[] urls = new String[]{
12             HOST_PATH + "lmm01.jpg",
13             HOST_PATH + "lmm02.jpg",
14             HOST_PATH + "lmm03.jpg",
15             HOST_PATH + "lmm04.jpg",
16             HOST_PATH + "lmm05.jpg",
17             HOST_PATH + "lmm06.jpg",
18             HOST_PATH + "lmm07.jpg",
19             HOST_PATH + "lmm08.jpg",
20             HOST_PATH + "lmm09.jpg",
21             HOST_PATH + "lmm10.jpg",
22             HOST_PATH + "lmm11.jpg",
23             HOST_PATH + "lmm12.jpg",
24             HOST_PATH + "lmm13.jpg",
25             HOST_PATH + "lmm14.jpg",
26             HOST_PATH + "lmm15.jpg",
27             HOST_PATH + "lmm16.jpg",
28             HOST_PATH + "lmm17.jpg",
29             HOST_PATH + "lmm18.jpg",
30             HOST_PATH + "lmm19.jpg",
31             HOST_PATH + "lmm20.jpg",
32             HOST_PATH + "lmm21.jpg",
33             HOST_PATH + "lmm22.jpg",
34             HOST_PATH + "lmm23.jpg",
35             HOST_PATH + "lmm24.jpg",
36             HOST_PATH + "lmm25.jpg",
37             HOST_PATH + "lmm26.jpg",
38             HOST_PATH + "lmm27.jpg",
39             HOST_PATH + "lmm28.jpg",
40             HOST_PATH + "lmm29.jpg",
41             HOST_PATH + "lmm30.jpg",
42             HOST_PATH + "lmm31.jpg",
43             HOST_PATH + "lmm32.jpg",
44             HOST_PATH + "lmm33.jpg"
45     };
46     @Override
47     protected void onCreate(Bundle savedInstanceState) {
48         super.onCreate(savedInstanceState);
49         setContentView(R.layout.activity_main);
50
51         lv = (ListView) findViewById(R.id.lv);
52
53         lv.setAdapter(new MyAdapter(this,urls));
54     }
55
56 }

4、MyAdapter

 1 package com.zyh.zyh_imageloader;
 2
 3 import android.content.Context;
 4 import android.view.LayoutInflater;
 5 import android.view.View;
 6 import android.view.ViewGroup;
 7 import android.widget.BaseAdapter;
 8 import android.widget.ImageView;
 9
10 public class MyAdapter extends BaseAdapter {
11     private Context context;
12     private LayoutInflater inflater;
13     private String[] data;
14     private ImageLoader imageLoader;
15     public MyAdapter(Context context, String[] data){
16         this.context = context;
17         inflater = LayoutInflater.from(this.context);
18         this.data = data;
19         imageLoader = ImageLoader.getInstance(context);
20     }
21     @Override
22     public int getCount() {
23         return data.length;
24     }
25
26     @Override
27     public Object getItem(int position) {
28         return data[position];
29     }
30
31     @Override
32     public long getItemId(int position) {
33         return position;
34     }
35
36     @Override
37     public View getView(int position, View convertView, ViewGroup parent) {
38         ViewHolder holder = null;
39         if(convertView == null){
40             holder = new ViewHolder();
41             convertView = inflater.inflate(R.layout.lv_item, null);
42             ImageView imageView = (ImageView) convertView.findViewById(R.id.iv);
43             holder.imageView = imageView;
44             convertView.setTag(holder);
45         }else{
46             holder = (ViewHolder) convertView.getTag();
47         }
48         imageLoader.loadImage(data[position], holder.imageView);
49
50         return convertView;
51     }
52
53     class ViewHolder{
54         ImageView imageView;
55     }
56
57 }

5、图片缓存构架类(主要类)

  1 package com.zyh.zyh_imageloader;
  2
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.FileNotFoundException;
  6 import java.io.FileOutputStream;
  7 import java.io.IOException;
  8 import java.io.InputStream;
  9 import java.lang.ref.SoftReference;
 10 import java.util.LinkedHashMap;
 11 import java.util.concurrent.ConcurrentHashMap;
 12
 13 import android.content.Context;
 14 import android.graphics.Bitmap;
 15 import android.graphics.BitmapFactory;
 16 import android.graphics.Color;
 17 import android.graphics.drawable.ColorDrawable;
 18 import android.os.AsyncTask;
 19 import android.widget.ImageView;
 20
 21 public class ImageLoader {
 22     private static Context context;
 23     private static final int MAX_CAPACITY = 20;//设置强引用的容量
 24     private DefaultImage defaultImage = new DefaultImage();//默认ImageView的颜色
 25     private static ImageLoader instance = null;
 26
 27     private ImageLoader(){}
 28     //构造函数
 29     private ImageLoader(Context context){
 30         this.context = context;
 31     }
 32
 33     //获取对象
 34     public static ImageLoader getInstance(Context context){
 35         if(instance == null){
 36             instance = new ImageLoader(context);
 37         }
 38         return instance;
 39     }
 40
 41     //一级缓存,强引用
 42     //0.75f是排序因子;true说明是访问排序;false基于插入排序
 43     //LRU最近最少使用算法
 44     private static LinkedHashMap<String, Bitmap> firstCacheMap = new LinkedHashMap<String, Bitmap>(MAX_CAPACITY, 0.75f, true){
 45         //根据返回值,移除map中最老的值
 46         protected boolean removeEldestEntry(java.util.Map.Entry<String,Bitmap> eldest) {
 47             if(this.size() > MAX_CAPACITY){
 48                 //加入二级缓存
 49                 secondCacheMap.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
 50                 //加入本地缓存
 51                 diskCache(eldest.getKey(), eldest.getValue());
 52                 //移除一级缓存
 53             }
 54             return false;
 55         };
 56     };
 57
 58     //二级缓存,软引用
 59     //线程安全的
 60     private static ConcurrentHashMap<String, SoftReference<Bitmap>> secondCacheMap = new ConcurrentHashMap<String, SoftReference<Bitmap>>();
 61
 62     /**
 63      * @desc 获取图片,如果从缓存中得不到,则从网络中获取
 64      * @param key
 65      * @param imageView
 66      */
 67     public void loadImage(String key, ImageView imageView){
 68         //从缓存中读取
 69         Bitmap bitmap = getFromCache(key);
 70         if(bitmap != null){
 71             //结束异步任务
 72             //cancelDownload(key, imageView);
 73
 74             imageView.setImageBitmap(bitmap);
 75         }else{
 76             //设置默认图片
 77             imageView.setImageDrawable(defaultImage);
 78
 79             //从网络中读取
 80             AsyncImageLoadTast tast = new AsyncImageLoadTast(imageView);
 81             tast.execute(key);
 82
 83         }
 84
 85     }
 86
 87     /**
 88      * @desc 取消下载
 89      * @param key
 90      * @param imageView
 91      */
 92     private void cancelDownload(String key, ImageView imageView) {
 93         //可能有多个异步任务在下载同一张图片
 94         AsyncImageLoadTast tast = new AsyncImageLoadTast(imageView);
 95         if(tast != null){
 96             String downloadKey = tast.key;//这个key从何而来
 97             if(downloadKey == null || downloadKey.equals(key)){
 98                 tast.cancel(true);
 99             }
100         }
101     }
102     protected static void diskCache(String key, Bitmap value) {
103         //采用md5方式作为图片名称
104         String fileName = MD5Utils.decode(key);
105         String path = context.getCacheDir().getAbsolutePath() + File.separator + fileName;
106
107         //jpg
108         FileOutputStream os = null;
109         try {
110             os = new FileOutputStream(path);
111             value.compress(Bitmap.CompressFormat.JPEG, 100, os);
112         } catch (FileNotFoundException e) {
113             // TODO Auto-generated catch block
114             e.printStackTrace();
115         }finally{
116             if(os != null){
117                 try {
118                     os.close();
119                 } catch (IOException e) {
120                     // TODO Auto-generated catch block
121                     e.printStackTrace();
122                 }
123             }
124         }
125
126     }
127
128     class AsyncImageLoadTast extends AsyncTask<String, Void, Bitmap>{
129         private String key;
130         private ImageView imageView;
131
132         public AsyncImageLoadTast(ImageView imageView) {
133             super();
134             this.imageView = imageView;
135         }
136
137         @Override
138         protected Bitmap doInBackground(String... params) {
139             key = params[0];
140             return download(key);
141         }
142
143         @Override
144         protected void onPostExecute(Bitmap result) {
145             super.onPostExecute(result);
146             if(isCancelled()){
147                 result = null;
148             }
149
150             if(result != null){
151                 //添加到一级缓存中去
152                 addFirstCache(key, result);
153                 //显示
154                 imageView.setImageBitmap(result);
155             }
156         }
157
158
159
160     }
161
162
163     private Bitmap getFromCache(String key) {
164         //从一级缓存中获取
165         synchronized(firstCacheMap){
166             Bitmap bitmap = firstCacheMap.get(key);
167             //为了保持最新使用
168             if(bitmap != null){
169                 firstCacheMap.remove(key);//????不是remove它的key吗?
170                 firstCacheMap.put(key, bitmap);
171                 return bitmap;
172             }
173         }
174
175         //从二级缓存中获取
176         SoftReference<Bitmap> soft_bitmap = secondCacheMap.get(key);
177         if(soft_bitmap != null){
178             Bitmap bitmap = soft_bitmap.get();
179             if(bitmap != null){
180                 //firstCacheMap.put(key, bitmap);
181                 addFirstCache(key, bitmap);
182                 return bitmap;
183             }
184         }else{
185             secondCacheMap.remove(key);
186         }
187
188         //从本地获取
189         Bitmap local_bitmap = getFromLocal(key);
190         if(local_bitmap != null){
191             //firstCacheMap.put(key, local_bitmap);
192             addFirstCache(key, local_bitmap);
193             return local_bitmap;
194         }
195         return null;
196     }
197
198
199
200
201
202     private Bitmap getFromLocal(String key) {
203         String fileName = MD5Utils.decode(key);
204         if(fileName == null){
205             return null;
206         }
207
208         String path = context.getCacheDir().getAbsolutePath() + File.separator + fileName;
209
210         FileInputStream is = null;
211         try {
212             is = new FileInputStream(path);
213             return BitmapFactory.decodeStream(is);
214         } catch (FileNotFoundException e) {
215             // TODO Auto-generated catch block
216             e.printStackTrace();
217         }finally{
218             if(is != null){
219                 try {
220                     is.close();
221                 } catch (IOException e) {
222                     // TODO Auto-generated catch block
223                     e.printStackTrace();
224                 }
225             }
226         }
227         return null;
228     }
229
230     public void addFirstCache(String key, Bitmap bitmap) {
231         if(bitmap != null){
232             synchronized(firstCacheMap){
233                 firstCacheMap.put(key, bitmap);
234             }
235         }
236     }
237
238
239
240
241
242     public Bitmap download(String key) {
243         InputStream is = null;
244         try {
245             is = HttpUtils.download(key);
246             return BitmapFactory.decodeStream(is);
247         } catch (Exception e) {
248             e.printStackTrace();
249         }finally{
250             if(is != null){
251                 try {
252                     is.close();
253                 } catch (IOException e) {
254                     e.printStackTrace();
255                 }
256             }
257         }
258         return null;
259     }
260
261     class DefaultImage extends ColorDrawable{
262         public DefaultImage(){
263             super(Color.BLUE);
264         }
265     }
266 }

6、辅助类

 1 package com.zyh.zyh_imageloader;
 2
 3 import java.io.InputStream;
 4 import java.net.HttpURLConnection;
 5 import java.net.URL;
 6
 7 public class HttpUtils {
 8     public static InputStream download(String key) throws Exception{
 9         HttpURLConnection conn = (HttpURLConnection) new URL(key).openConnection();
10         return conn.getInputStream();
11     }
12 }
 1 package com.zyh.zyh_imageloader;
 2
 3 import java.io.UnsupportedEncodingException;
 4 import java.security.MessageDigest;
 5 import java.security.NoSuchAlgorithmException;
 6
 7 public class MD5Utils {
 8     public static String decode(String info){
 9         try
10           {
11             MessageDigest md5 = MessageDigest.getInstance("MD5");
12             md5.update(info.getBytes("UTF-8"));
13             byte[] encryption = md5.digest();
14
15             StringBuffer strBuf = new StringBuffer();
16             for (int i = 0; i < encryption.length; i++)
17             {
18               if (Integer.toHexString(0xff & encryption[i]).length() == 1)
19               {
20                 strBuf.append("0").append(Integer.toHexString(0xff & encryption[i]));
21               }
22               else
23               {
24                 strBuf.append(Integer.toHexString(0xff & encryption[i]));
25               }
26             }
27
28             return strBuf.toString();
29           }
30           catch (NoSuchAlgorithmException e)
31           {
32             return "";
33           }
34           catch (UnsupportedEncodingException e)
35           {
36             return "";
37           }
38     }
39 }
时间: 2024-10-28 04:48:24

图片缓存构架的相关文章

Android:ViewPager扩展详解——带有导航的ViewPagerIndicator(附带图片缓存,异步加载图片)

大家都用过viewpager了, github上有对viewpager进行扩展,导航风格更加丰富,这个开源项目是ViewPagerIndicator,很好用,但是例子比较简单,实际用起来要进行很多扩展,比如在fragment里进行图片缓存和图片异步加载. 下面是ViewPagerIndicator源码运行后的效果,大家也都看过了,我多此一举截几张图: 下载源码请点击这里 ===========================================华丽的分割线==============

麦子学院ios笔记:IOS把图片缓存到本地的几种方法

把ios的图片缓存到本地的方法有几种?现在来看看学生在麦子学院学习ios开发的笔记中有讲到哪几种方法呢? <code>把图片缓存到本地,在很多场景都会用到,如果是只储存文字信息,那建一个plist文件,或者数据库就能很方便的解决问题,但是如果存图片到沙盒就没那么方便了.这里介绍两种保存图片到沙盒的方法. </code> 一.把图片转为base64的字符串存到数据库中或者plist文件中,然后用到的时候再取出来 <code class="hljs" obje

AFN清除图片缓存 以及菊花转圈

AFNetworking网络库已经提供了很好的图片缓存机制,效率是比较高的,但是我发现没有直接提供清除缓存的功能,可项目通常都需要添加 清除功能的功能,因此,在这里我以UIImageView+AFNetworking类中添加了下面一个清除功能方法: [objc] view plaincopyprint? /** Clear image cache author: huangyibiao */ + (void)clearCache; [objc] view plaincopyprint? /**

Android图片缓存分析(一)

Android中写应用时,经常会遇到加载图片的事,由于很多图片是网络上下载获取的,当我们进页面时,便会去网络下载图片,一两次可能没啥问题,但如果同一张图片每次都去网络拉取,不仅速度慢,更影响用户体验,同时会浪费用户的流量. 基于此,很多人便想到了图片缓存的方法. 现在比较普遍的图片缓存主要有以下几个步骤: 一.从缓存中获取图片 二.如果缓存中未获取图片,则从存储卡中获取 三.如果存储卡中未获取图片,则从网络中获取 一.从缓存中获取图片 我们知道,Android中分配给每个应用的内存空间是有限的,

图片缓存策略

图片缓存策略 1.图片缓存策略分析 从网络上加载一张图,然后把它显示到UI上是个很简单的事情.当图片变多时,处理起来就有些麻烦了,很典型的应用场景,如ListView,GridView或者ViePager等.我们既需要保证用户看到更多的图片,以免屏幕出现大面积的空白,又要保证内存能Hold住. GC会自动释放一个没有强引用的图片或者View,这本来是个好事情,但为了让用户来回滚动时还能快速加载老图片,通常会使用图片缓存. 下面分别讨论下,通过使用Memory Cache和Disk Cache来增

Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解

本篇文章继续为大家介绍Universal-Image-Loader这个开源的图片加载框架,介绍的是图片缓存策略方面的,如果大家对这个开源框架的使用还不了解,大家可以看看我之前写的一篇文章Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用,我们一般去加载大量的图片的时候,都会做缓存策略,缓存又分为内存缓存和硬盘缓存,我之前也写了几篇异步加载大量图片的文章,使用的内存缓存是LruCache这个类,LRU是Least Recently Used 近

Android公共库——图片缓存 网络缓存 下拉及底部更多ListView 公共类

Android公共库--图片缓存 网络缓存 下拉及底部更多ListView 公共类 转载自http://www.trinea.cn/android/android-common-lib/ 介绍总结的一些android公共库,包含缓存(图片缓存.预取缓存.网络缓存).公共View(下拉及底部加载更多ListView.底部加载更多ScrollView.滑动一页Gallery).及Android常用工具类(网络.下载.shell.文件.json等等). TrineaAndroidCommon已开源,地

Android 三大图片缓存原理、特性对比

这是我在 MDCC 上分享的内容(略微改动),也是源码解析第一期发布时介绍的源码解析后续会慢慢做的事. 从总体设计和原理上对几个图片缓存进行对比,没用到他们的朋友也可以了解他们在某些特性上的实现. 上篇关于选择开源项目的好处及如何选择开源项目可见:开源项目使用及选型. 一. 四大图片缓存基本信息 Universal ImageLoader 是很早开源的图片缓存,在早期被很多应用使用. Picasso 是 Square 开源的项目,且他的主导者是 JakeWharton,所以广为人知. Glide

android使用ImageLoader实现图片缓存(安卓开发必备)

相信大家在学习以及实际开发中基本都会与网络数据打交道,而这其中一个非常影响用户体验的就是图片的缓存了,若是没有弄好图片缓存,用户体验会大大下降,总会出现卡顿情况,而这个问题尤其容易出现在ListView中的Item有图片的情况中. 前面与大家分享了一个网络连接框架Retrofit,里面也有类似的图片加载的picasso,大家都可以去体验,直通车:http://www.cnblogs.com/liushilin/p/5680135.html 当然还有当前我认为最好用的图片缓存加载框架Fresco,