Android缓存机制——DiskLruCache在硬盘中缓存

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaihaohao1/article/details/83539170

一、Android中的缓存策略
一般来说,缓存策略主要包含缓存的添加、获取和删除这三类操作。如何添加和获取缓存这个比较好理解,那么为什么还要删除缓存呢?这是因为不管是内存缓存还是硬盘缓存,它们的缓存大小都是有限的。当缓存满了之后,再想其添加缓存,这个时候就需要删除一些旧的缓存并添加新的缓存。

因此LRU(Least Recently Used)缓存算法便应运而生,LRU是近期最少使用的算法,它的核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。采用LRU算法的缓存有两种:LrhCache和DiskLruCache,分别用于实现内存缓存和硬盘缓存,其核心思想都是LRU缓存算法。

二、出处
DiskLruCache不是Google官方编写,但获得官方认证。所以在写的时候要先下载他源码 DiskLruCache 文件,复制到项目中
下载地址:https://download.csdn.net/download/sinyu890807/7709759

三、使用
工具类DiskCacheUtil

package com.zhh.app;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment;

import java.io.File;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Created by Ivan on 2016/11/22.
 */

public class DiskCacheUtil {
    /**
     * 获取App 缓存路径
     *
     * @param context
     * @param uniqueName
     * @return
     */
    public static File getDiskCacheDir(Context context, String uniqueName) {
        String cachePath = null;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) {
            cachePath = context.getExternalCacheDir().getPath();
        } else {
            cachePath = context.getCacheDir().getPath();
        }
        return new File(cachePath + File.separator + uniqueName);
    }


    /**
     * 获取APP版本号
     *
     * @param context
     * @return
     */
    public static int getAppVersionCode(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            return info.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

    /**
     * 初始化DiskLruCache
     *
     * @param context
     */
    public static DiskLruCache initDiskLruCache(Context context) {
        DiskLruCache mDiskLruCache = null;
        try {
            File cacheDir = getDiskCacheDir(context, "bitmap");
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
//          图片占的最大内存是20M
            mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersionCode(context), 1, 20 * 1024 * 1024);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mDiskLruCache;

    }


    /**
     * 获取MD5 编码
     * 把图片路径 通过 MD5 转换成 要存储的文件名
     * 将图片的URL进行MD5编码,编码后的字符串肯定是唯一的,并且只会包含0-F这样的字符,完全符合文件的命名规则
     *
     * @param key
     * @return
     */
    public static String getMd5String(String key) {
        String cacheKey;
        try {
            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
            mDigest.update(key.getBytes());
            cacheKey = bytesToHexString(mDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            cacheKey = String.valueOf(key.hashCode());
        }
        return cacheKey;
    }

    private static String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }
}

MainActivity中使用

package com.zhh.app;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

import com.orhanobut.logger.Logger;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends Activity {
//  读取图片的按钮
    private Button button;
//  删除缓存的按钮
    private Button button3;
//  图片
    private ImageView imageView;
//  上下文对象
    private Context context;
    String imgurl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
//  DiskLruCache对象
    DiskLruCache diskLruCache;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = MainActivity.this;
        diskLruCache = DiskCacheUtil.initDiskLruCache(context);
        button = (Button)findViewById(R.id.button);
        button3 = (Button)findViewById(R.id.button3);
        imageView = (ImageView)findViewById(R.id.imageView);
//      读取图片
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getData();

            }
        });
//      移除缓存
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                remove();
            }
        });
    }

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            switch (msg.what) {
                case  1:
                    try {
//                     从文件中读取
                        String key = DiskCacheUtil.getMd5String(imgurl);
                        DiskLruCache.Snapshot snapShot = diskLruCache.get(key);
                        if (snapShot != null) {
                            InputStream is = snapShot.getInputStream(0);
                            Bitmap bitmap = BitmapFactory.decodeStream(is);
                            imageView.setImageBitmap(bitmap);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    break;
            }

        }
    };
    /**
     *
     * 存入数据 存入的是 流 对象
     * 从网络中读取数据,保存到文件中
     */
    private void dataPut(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String imageUrl = imgurl;
                    String key =DiskCacheUtil.getMd5String(imageUrl);
                    DiskLruCache.Editor editor = diskLruCache.edit(key);
                    if (editor != null) {
                        OutputStream outputStream = editor.newOutputStream(0);
//                      写到这个流里面
                        if (downloadUrlToStream(imageUrl, outputStream)) {
                            editor.commit();
//                          从网络中获取数据,并且已经保存到文件中
//                          发消息,从文件中读取
                            handler.sendEmptyMessage(1);
                        } else {
                            editor.abort();
                        }
                    }
                    diskLruCache.flush();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 下载图片
     * @param urlString
     * @param outputStream
     * @return
     */
    private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
        HttpURLConnection urlConnection = null;
        BufferedOutputStream out = null;
        BufferedInputStream in = null;
        try {
            final URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();
            in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
            out = new BufferedOutputStream(outputStream, 8 * 1024);
            int b;
            while ((b = in.read()) != -1) {
//              写到这个流里面
                out.write(b);
            }
            return true;
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 从文件中读取数据
     * 取出的是 流 对象
     */
  private  void getData(){
      try {
          String key = DiskCacheUtil.getMd5String(imgurl);
          DiskLruCache.Snapshot snapShot = diskLruCache.get(key);
//        从缓存中读取
          if (snapShot != null) {
              Logger.t("111").d("从文件中读取");
              InputStream is = snapShot.getInputStream(0);
              Bitmap bitmap = BitmapFactory.decodeStream(is);
              imageView.setImageBitmap(bitmap);

          }else{
//        从网络中读取
              Logger.t("111").d("从网络中读取");
              dataPut();
          }
      } catch (IOException e) {
          e.printStackTrace();
      }
  }
    /**
     * 移除缓存
     */
    private void remove(){
        try {
            String key = DiskCacheUtil.getMd5String(imgurl);
            diskLruCache.remove(key);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }





}

activity_main.xml中

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    >

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="读取数据"
        />

    <Button
        android:id="@+id/button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="移除缓存"
        />
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

开权限:

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

参考文章
https://blog.csdn.net/guolin_blog/article/details/28863651
源码下载
huancun-----app2
https://download.csdn.net/download/zhaihaohao1/10752735

猜你喜欢

转载自blog.csdn.net/zhaihaohao1/article/details/83539170