版权声明:本文为博主原创文章,未经博主允许不得转载。 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