Android图片的三级缓存demo
三级缓存概述
1,网络缓存, 不优先加载, 速度慢,浪费流量
2,本地缓存, 次优先加载, 速度快
3,内存缓存, 优先加载, 速度最快
缓存策略
首次加载时,通过网络来获取数据,将数据保存至本地和内存中
再次加载时,优先访问内存中的缓存,若内存中没有,则加载本地中的缓存
缓存的封装
ThreeLevelCache.java类
通过ThreeLevelCache.instance(this).display(mIv,url);
即可调用
代码如下:
public class ThreeLevelCache {
private static ThreeLevelCache mInstance;
private NetworkCatche mNetworkCatche;
private LocalCache mLocalCache;
private MemoryCache mMemoryCache;
public static ThreeLevelCache instance(Context context){
if(null == mInstance){
synchronized (ThreeLevelCache.class){
if(null == mInstance) {
mInstance = new ThreeLevelCache(context);
}
}
}
return mInstance;
}
private ThreeLevelCache(Context context){
mMemoryCache = new MemoryCache();
mLocalCache = new LocalCache(context);
mNetworkCatche = new NetworkCatche(mMemoryCache,mLocalCache);
}
public void display(ImageView iv, String url){
iv.setImageResource(R.mipmap.ic_launcher);
Bitmap bm;
//get cache form memory
bm = mMemoryCache.getBitmapCacheFromMemory(url);
if(null != bm){
iv.setImageBitmap(bm);
Log.d("song--->","get cache form memory");
return;
}
//get cache form local
bm = mLocalCache.getBitmapCacheFromLocal(url);
if(null != bm){
iv.setImageBitmap(bm);
Log.d("song--->","get cache form local");
return;
}
//get cache form net
mNetworkCatche.getBitmapFromNet(iv,url);
}
}
网络缓存
从网络获取数据,获取成功之后对数据进行压缩。然后缓存到本地和内存中。
代码如下:
public class NetworkCatche {
private MemoryCache mMemoryCache;
private LocalCache mLocache;
public NetworkCatche(MemoryCache memoryCache, LocalCache localCache) {
mMemoryCache = memoryCache;
mLocache = localCache;
}
public void getBitmapFromNet(ImageView iv, String url) {
new BitmapTast().execute(iv,url);
}
class BitmapTast extends AsyncTask<Object,Void,Bitmap>{
private ImageView iv;
private String url;
/**
* do in thread
* @param objects o
* @return bitmap
*/
@Override
protected Bitmap doInBackground(Object... objects) {
iv = (ImageView) objects[0];
url = (String) objects[1];
return downLoadBitmap(url);
}
/**
* update progress
* @param values v
*/
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
/**
* call after doInBackground
* @param bitmap bm
*/
@Override
protected void onPostExecute(Bitmap bitmap) {
if(null != bitmap){
iv.setImageBitmap(bitmap);
Log.d("song--->","first get data form net");
//add cache to Local
mLocache.setBitmapCacheFromLocal(url,bitmap);
//add cache to memory
mMemoryCache.setBitmapCacheFromMemory(url,bitmap);
}
}
}
/**
* get bitmap form net
* @param url image url
* @return bitmap of image
*/
private Bitmap downLoadBitmap(String url) {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(5*1000);
conn.setReadTimeout(5*1000);
conn.setRequestMethod("GET");
conn.connect();
int responseCode = conn.getResponseCode();
if(200 == responseCode){//200 == request respon ok
//压缩图片
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//取样压缩原来的1/2
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
return BitmapFactory.decodeStream(conn.getInputStream(),null,options);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
conn.disconnect();
}
return null;
}
}
本地缓存
同过数据的url进行MD5加密作为文件名缓存到本地。
代码如下:
public class LocalCache {
private Context mContext;
public LocalCache(Context ctx){
mContext = ctx;
}
/**
* get cache form local
* @param url cache url
* @return bitmap
*/
public Bitmap getBitmapCacheFromLocal(String url) {
String name = null;
try {
name = MD5Encoder.encode(url);
File file = new File(getCachePath(),name);
if(file.exists()) {
//return BitmapFactory.decodeStream(new FileInputStream(file));
return BitmapFactory.decodeFile(file.getAbsolutePath());
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* save bitmap to local
* @param url bitmap url
* @param bitmap bitmap
*/
public void setBitmapCacheFromLocal(String url, Bitmap bitmap) {
String name ;
FileOutputStream fos = null;
try {
name = MD5Encoder.encode(url);
File file = new File(getCachePath(),name);
File parentFile = file.getParentFile();
if(!parentFile.exists())
parentFile.mkdirs();
//save bitmap to local file
fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);
Log.d("song--->","save cache to local");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* get cache path
* @return path
*/
private String getCachePath(){
String state = Environment.getExternalStorageState();
String path = "LocalCache/"+mContext.getPackageName()+"/data";
File dir;
if(!TextUtils.isEmpty(state) && Environment.MEDIA_MOUNTED.equals(state)){
//has sdCard
dir = new File(Environment.getExternalStorageDirectory(),path);
} else {
//no scCard
dir = new File(mContext.getCacheDir(),path);
}
return dir.getAbsolutePath();
}
}
内存缓存
Android 虚拟机默认分配给每个应用 16M的内存空间,真机会比16M大。
内存缓存使用LruCache
public class MemoryCache {
private LruCache<String,Bitmap> mLruCach;
public MemoryCache(){
long maxMemory = Runtime.getRuntime().maxMemory()/8;
mLruCach = new LruCache<String, Bitmap>((int)maxMemory){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
};
}
public Bitmap getBitmapCacheFromMemory(String url) {
return mLruCach.get(url);
}
public void setBitmapCacheFromMemory(String url, Bitmap bitmap) {
mLruCach.put(url,bitmap);
Log.d("song--->","save cache to memory");
}
}
MD5Encoder
MD5Encoder是从网上找的,顺便也贴出来,代码如下:
class MD5Encoder {
/**
* encode
* @param string source string
* @return encode string
* @throws Exception e
*/
public static String encode(String string) throws Exception{
String MD5 = "MD5";
String UTF_8 = "UTF-8";
byte[] hash = MessageDigest.getInstance(MD5).digest(string.getBytes(UTF_8));
StringBuffer hex = new StringBuffer(hash.length * 2);
for(byte b:hash){
if((b & 0xFF)<0x10){
hex.append("0");
}
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString();
}
}
Tips网络权限和SDcard的读写权限
记得在配置文件AndroidManifest.xml
里面给以下权限:
<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"/>
demo地址
感兴趣的可以去下载玩玩,点击传送
文章参考
https://blog.csdn.net/lovoo/article/details/51456515
https://blog.csdn.net/ChatHello/article/details/70573351