Android--图片的三级缓存策略

三级缓存
缓存(内存)--->本地磁盘---->网络

1、首先看一下图片存储到本地磁盘
 1 public class FileUtils {
 2 
 3     String path;//文件存储的地方
 4     public FileUtils(Context context,String dirName){//文件夹的名称
 5 
 6         if(Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED){//SD卡就绪
 7             //文件可以放在SD卡中
 8             path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+dirName;
 9         }else{
10             //文件放在内部存储器里
11             path = context.getCacheDir().getAbsolutePath()+"/"+dirName;
12         }
13 
14         new File(path).mkdirs();
15     }
16 
17     //读取和写入
18     public void saveToSDCard(String key, Bitmap bmp){
19         FileOutputStream fos = null;
20         try {
21             fos = new FileOutputStream(new File(path,key));
22 
23         } catch (FileNotFoundException e) {
24             e.printStackTrace();
25         }
26         //保存固定格式图片,不压缩
27         bmp.compress(Bitmap.CompressFormat.PNG,100,fos);
28 
29         try {
30             fos.close();
31         } catch (IOException e) {
32             e.printStackTrace();
33         }
34     }
35     //读取
36     public Bitmap readFromSDCard(String key){
37         return BitmapFactory.decodeFile(new File(path,key).getAbsolutePath());
38     }
39 }
FileUtils.java

 2、图片加载,先加载缓存图片,缓存没有再到本地加载,本地没有再到网络加载 

  1 public class ImageLoader {
  2     /**
  3      * 缓存类
  4      * LruCache原理:Cache保存一个强引用来限制内容数量。每当Item被访问的时候,此Item就会移动到队列的头部。
  5      * 当cache已满的时候加入新的item时,在队列尾部的item会被回收。
  6      * 解释:当超出指定内存值则移除最近最少用的图片内存
  7      */
  8     private static LruCache<String,Bitmap> cache;
  9     private FileUtils fileUtils;
 10     //使用线程池
 11     ExecutorService threadLooper;
 12 
 13     public ImageLoader(Context context,String dirName){
 14         //获取系统分配的最大内存
 15         cache = new LruCache<String,Bitmap>((int) (Runtime.getRuntime().maxMemory()/8)){
 16            //判断每一个键对应得值得大小
 17             //自动释放使用频率低的文件
 18             @Override
 19             protected int sizeOf(String key, Bitmap value) {
 20                 return value.getByteCount();//也可以value.getWidth()*value.getHeight()
 21             }
 22         };
 23         fileUtils = new FileUtils(context,dirName);
 24         threadLooper = Executors.newFixedThreadPool(5);
 25 
 26     }
 27 
 28     //存储到缓存
 29     private void saveToCache(String key, Bitmap bmp){
 30         cache.put(key,bmp);
 31     }
 32 
 33     //从缓存中读取
 34     private Bitmap readFromCache(String key){
 35         return cache.get(key);
 36     }
 37 
 38     public void loadImage(final String url, @NonNull final ImageLoadListener listener){
 39 
 40         final String key = url.replaceAll("[\W]","");//非单次类型用空替换
 41         //第一级,缓存
 42         if(readFromCache(key)!=null){
 43             //缓存已存在,直接拿出来,但是,不是直接返回,因为后面还有请求网络,并不能确定什么时候返回。这里使用回调
 44             listener.loadImageFinish(readFromCache(key));
 45             Log.e("TAG","从缓存中加载");
 46         }else {
 47             //第二级,本地磁盘
 48             Bitmap bitmap = fileUtils.readFromSDCard(key);
 49             if(bitmap!=null){
 50                 //存储到缓存
 51                 saveToCache(key,bitmap);
 52                 //返回
 53                 listener.loadImageFinish(fileUtils.readFromSDCard(key));
 54                 Log.e("TAG","从SDCard中加载");
 55             }else{
 56 
 57                 Log.e("TAG","从网络下载");
 58                 final Handler handler = new Handler(){
 59                     @Override
 60                     public void handleMessage(Message msg) {
 61                         super.handleMessage(msg);
 62                         listener.loadImageFinish((Bitmap) msg.obj);
 63                     }
 64                 };
 65 
 66                 //下载,使用线程池
 67                 threadLooper.execute(new Runnable() {
 68                     @Override
 69                     public void run() {
 70                         //开始下载,子线程
 71                         try {
 72 
 73                             Bitmap bitmap1 = BitmapFactory.decodeStream(new URL(url).openStream());
 74                             //保存到本地,保存到缓存
 75                             fileUtils.saveToSDCard(key,bitmap1);
 76                             saveToCache(key,bitmap1);
 77 
 78                             //使用异步任务通知主线程修改UI
 79                             Message msg = handler.obtainMessage();
 80                             msg.obj = bitmap1;
 81                             handler.sendMessage(msg);
 82 
 83                         } catch (IOException e) {
 84                             e.printStackTrace();
 85                         }
 86 
 87                     }
 88                 });
 89 
 90             }
 91         }
 92     }
 93 
 94     public void cancelDowload(){
 95         threadLooper.shutdown();
 96     }
 97 
 98     public interface ImageLoadListener{
 99         void loadImageFinish(Bitmap bitmap);
100     }
101 }
ImageLoader.java

  3、NetworkImageView自定义View,继承自ImageView

res/values/创建network_attrs.xml

1 <resources>
2     <declare-styleable name="NetworkImageView">
3         <attr name="url" format="string"/>
4     </declare-styleable>
5 </resources>
network_attrs.xml
 1 public class NetworkImageView extends ImageView{
 2 
 3     String url;
 4     ImageLoader loader;
 5 
 6     public NetworkImageView(Context context) {
 7         super(context);
 8     }
 9 
10     public NetworkImageView(Context context, AttributeSet attrs) {
11         super(context, attrs);
12         //获取自定义属性
13         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NetworkImageView);
14         url = a.getString(R.styleable.NetworkImageView_url);
15         a.recycle();
16         loader = new ImageLoader(context,"network");
17         if(url!=null){
18             setUrl(url);
19         }
20     }
21 
22     public String getUrl() {
23         return url;
24     }
25 
26     public void setUrl(String url) {
27         this.url = url;
28         //设置到图片上去
29         loader.loadImage(url, new ImageLoader.ImageLoadListener() {
30             @Override
31             public void loadImageFinish(Bitmap bitmap) {
32                 setImageBitmap(bitmap);
33             }
34         });
35     }
36 }
NetworkImageView.java

4、测试

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     android:id="@+id/activity_main"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     android:orientation="vertical"
 8     tools:context="com.example.lesson19_threecache.MainActivity">
 9 
10     <Button
11         android:layout_width="match_parent"
12         android:layout_height="wrap_content"
13         android:onClick="start"
14         android:text="加载图片" />
15 
16     <ImageView
17         android:id="@+id/iv"
18         android:layout_width="wrap_content"
19         android:layout_height="wrap_content"
20         android:src="@mipmap/ic_launcher" />
21 
22     <com.example.mylibrary.widget.NetworkImageView
23         android:layout_width="wrap_content"
24         android:layout_height="wrap_content"
25         app:url="http://ent.chinadaily.com.cn/img/site1/20161117/448a5bd66b8519976e9933.jpeg"/>
26 </LinearLayout>
activity_main.xml
 1 public class MainActivity extends AppCompatActivity {
 2 
 3     ImageView iv;
 4     ImageLoader loader;
 5     @Override
 6     protected void onCreate(Bundle savedInstanceState) {
 7         super.onCreate(savedInstanceState);
 8         setContentView(R.layout.activity_main);
 9         iv = (ImageView) findViewById(R.id.iv);
10         loader = new ImageLoader(this,"three_cache");
11     }
12 
13     public void start(View v){
14 
15         loader.loadImage("http://image.cqcb.com/d/file/personage/2016-11-17/9b05cf89592d3e3eb2027519fbb98214.jpg", new ImageLoader.ImageLoadListener() {
16             @Override
17             public void loadImageFinish(Bitmap bitmap) {
18                 iv.setImageBitmap(bitmap);
19             }
20         });
21     }
MainActivity.java
 
原文地址:https://www.cnblogs.com/Claire6649/p/6075388.html