本篇介绍Android中的三级缓存机制
参考网址:https://www.cnblogs.com/huangjie123/p/6130665.html
三级缓存指的是:内存缓存、本地缓存、网络缓存。
其各自的特点是内存缓存速度快, 优先读取,本地缓存速度其次, 内存没有,读本地,网络缓存速度最慢, 本地也没有,才访问网络。
对于网络缓存理解起来较为容易直接从网络中获取资源,本地缓存可以存在SD卡中,内存缓存一般存在数组或集合中。
下面我们从三部分来透析缓存机制
一、内存缓存
内存中读数据需要用到最近最少引用的算法(lrucache)。Lrucache算法要求为new LruCache<>() 传入一个分配给软件的最大内存,同时重写sizeof()方法,计算每一张图片的大小。
这样就可以直接调用LruCache的put()和get()方法。
二、本地缓存
当发现内存中没有数据时,找到SD卡中的存储文件。
通过Bitmap的compress()方法向文件夹中写数据,通过位图工厂BitmapFactory的decodeStream()读取数据,同时可以为decodeStream()方法传入options参数,缩小图片。
三、网络缓存
本地仍然没有获取数据,再从网络获取。
网络获取数据可以用异步任务来执行(耗时操作不能再主线程中执行)。
异步任务需要重写onPostExecute()方法和doInBackground()方法。
doInBackground()方法中访问网路,这里用到的是Httpurlconnection,通过连接得到输入流,利用位图工厂转换成位图,返回。onPostExecute()方法在doInBackground()方法执行后执行,传入的参数数doInBackground()方法的返回值。
代码调用和缓存工具类如下:
public class NextActivity extends AppCompatActivity{
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
getBitmap();
}
private void getBitmap() {
iv = (ImageView) findViewById(R.id.iv_next);
CacheUtils utils =
new CacheUtils();
utils.display(iv,
"http://a.hiphotos.baidu.com/image/pic/item/a9d3fd1f4134970a489111e59ccad1c8a6865d1d.jpg");
}
}
布局就是一个ImageView,此处省略布局了。
下面我们看缓存工具类:
1、总工具类
import android.graphics.Bitmap;
import android.widget.ImageView;
import com.dota.musicapp.utils.L;
/**
* 三级缓存的管理工具类
* Created by ${Dota.Wang} on 2017/11/25.
*/
public class CacheUtils {
private MemoryCacheUtils mMemoryCacheUtils;
private LocalCacheUtils mLocalCacheUtils;
private NetCacheUtils mNetCacheUtils;
public CacheUtils() {
mMemoryCacheUtils =
new MemoryCacheUtils();
mLocalCacheUtils =
new LocalCacheUtils();
mNetCacheUtils =
new NetCacheUtils(mMemoryCacheUtils, mLocalCacheUtils);
}
public void display(ImageView imageView, String url) {
Bitmap bitmap = mMemoryCacheUtils.getBitmapToMemory(url);
if (bitmap !=
null) {
imageView.setImageBitmap(bitmap);
L.i(
"diaplay: 221111111111");
return;
}
bitmap = LocalCacheUtils.getBitmapToLoacl(url);
if (bitmap !=
null) {
L.i(
"diaplay: 1111111");
imageView.setImageBitmap(bitmap);
mMemoryCacheUtils.putBitmapToMemory(bitmap, url);
return;
}
mNetCacheUtils.getBitmapFromNet(imageView, url);
}
}
2、内存缓存工具类
import android.graphics.Bitmap;
import android.util.LruCache;
import com.dota.musicapp.utils.L;
/**
* 第一级缓存:内存缓存的工具类
* Created by ${Dota.Wang} on 2017/11/25.
*/
public class MemoryCacheUtils {
private LruCache<String, Bitmap> mMemoryCache;
public MemoryCacheUtils() {
int maxmemory = (
int) Runtime.getRuntime().maxMemory();
L.i(
"MemoryCacheUtils: " + maxmemory);
mMemoryCache =
new LruCache<String, Bitmap>(maxmemory /
8) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
}
public void putBitmapToMemory(Bitmap bitmap, String url) {
L.i(
"putBitmapToMemory: ");
mMemoryCache.put(url, bitmap);
}
public Bitmap
getBitmapToMemory(String url) {
L.i(
"getBitmapToMemory: ");
Bitmap bitmap = mMemoryCache.get(url);
return bitmap;
}
}
3、本地缓存工具类
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import com.dota.musicapp.utils.L;
import com.dota.musicapp.utils.Md5Utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/**
* 第二级缓存:本地缓存(SD卡)的工具类
* Created by ${Dota.Wang} on 2017/11/25.
*/
public class LocalCacheUtils {
public static void putBitmapToLoacl(Bitmap bitmap, String url) {
String encode = Md5Utils.encode(url);
File file =
new File(Environment.getExternalStorageDirectory(), encode);
L.i(
"putBitmapToLoacl: " + file.toString());
File parent = file.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
try {
bitmap.compress(Bitmap.CompressFormat.JPEG,
100,
new FileOutputStream(file));
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static Bitmap
getBitmapToLoacl(String url) {
String encode = Md5Utils.encode(url);
File file =
new File(Environment.getExternalStorageDirectory(), encode);
if (file.exists()) {
BitmapFactory.Options opts =
new BitmapFactory.Options();
opts.inSampleSize =
3;
try {
Bitmap bitmap = BitmapFactory.decodeStream(
new FileInputStream(file),
null, opts);
return bitmap;
}
catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
return null;
}
}
4、网络缓存工具类
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* 第三级缓存:网络缓存的工具类
* Created by ${Dota.Wang} on 2017/11/25.
*/
public class NetCacheUtils {
private MemoryCacheUtils mMemoryCacheUtils;
private LocalCacheUtils mLocalCacheUtils;
public NetCacheUtils(MemoryCacheUtils mMemoryCacheUtils, LocalCacheUtils mLocalCacheUtils) {
this.mLocalCacheUtils = mLocalCacheUtils;
this.mMemoryCacheUtils = mMemoryCacheUtils;
}
public void getBitmapFromNet(ImageView imageView, String url) {
imageView.setTag(url);
Bitmaptask task =
new Bitmaptask();
task.execute(imageView, url);
}
class Bitmaptask extends AsyncTask<Object, Void, Bitmap> {
private HttpURLConnection urlConnection;
private ImageView imageView;
private String url;
@Override
protected void onPostExecute(Bitmap bitmap) {
if (bitmap !=
null) {
if (url.equals(imageView.getTag())) {
imageView.setImageBitmap(bitmap);
System.out.print(
"onPostExecute");
mLocalCacheUtils.putBitmapToLoacl(bitmap, url);
mMemoryCacheUtils.putBitmapToMemory(bitmap, url);
}
}
}
@Override
protected Bitmap
doInBackground(Object[] params) {
imageView = (ImageView) params[
0];
url = (String) params[
1];
Bitmap bitmap = downloadFromNet(url);
return bitmap;
}
private Bitmap
downloadFromNet(String url) {
try {
urlConnection = (HttpURLConnection)
new URL(url).openConnection();
urlConnection.setConnectTimeout(
5000);
urlConnection.setRequestMethod(
"GET");
int responseCode = urlConnection.getResponseCode();
if (responseCode ==
200) {
InputStream inputStream = urlConnection.getInputStream();
BitmapFactory.Options opts =
new BitmapFactory.Options();
opts.inSampleSize =
2;
Bitmap bitmap = BitmapFactory.decodeStream(inputStream,
null, opts);
return bitmap;
}
}
catch (IOException e) {
e.printStackTrace();
return null;
}
finally {
urlConnection.disconnect();
}
return null;
}
}
}
5、本地缓存中用到的Md5Utils工具类
import java.security.MessageDigest;
/**
* Created by ${Dota.Wang} on 2017/11/25.
*/
public class Md5Utils {
public static String
encode(String pwd) {
try {
MessageDigest digest = MessageDigest.getInstance(
"md5");
byte[] bs = digest.digest(pwd.getBytes());
StringBuilder sb =
new StringBuilder();
for (
byte b : bs) {
int number = b &
0xff;
String str = Integer.toHexString(number);
if (str.length() ==
1) {
sb.append(
"0");
}
sb.append(number);
}
return sb.toString();
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
6、最后,注意注册表中对权限的添加
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />