三级缓存:
内存缓存:优先加载,速度最快
本地内存:速度其次,内存没有,读本地
网络缓存:速度最慢,本地也没有,才访问网络
我们定义一个图片加载类:
MyBitmapUtils.java
/**
* 自定义图片加载工具
* @author dream
*
*/
public class MyBitmapUtils {
NetCacheUtils mNetCacheUtils;
LocalCacheUtils mLocalCacheUtils;
MemoryCacheUtils mMemoryCacheUtils;
public MyBitmapUtils() {
mMemoryCacheUtils = new MemoryCacheUtils();
mLocalCacheUtils = new LocalCacheUtils();
mNetCacheUtils = new NetCacheUtils(mLocalCacheUtils,mMemoryCacheUtils);
}
public void display(ImageView ivPic, String url) {
ivPic.setImageResource(R.drawable.news_pic_default);
Bitmap bitmap = null;
bitmap = mMemoryCacheUtils.getBitmapFromMemory(url);
if(bitmap != null)
{
ivPic.setImageBitmap(bitmap);
return;
}
//从本地读
bitmap = mLocalCacheUtils.getBitmapFromLocal(url);
if(bitmap != null)
{
ivPic.setImageBitmap(bitmap);
mMemoryCacheUtils.setBitmapToMemory(url, bitmap); //将图片保存在内存
return;
}
//从过网络读
mNetCacheUtils.getBitmapFromNet(ivPic, url);
}
}
从网络获取的类:
NetCacheUtils.java
/**
* 网络缓存
* @author dream
*
*/
public class NetCacheUtils {
private HttpURLConnection conn = null;
private LocalCacheUtils mLocalCacheUtils;
private MemoryCacheUtils mMemoryCacheUtils;
public NetCacheUtils(LocalCacheUtils mLocalCacheUtils, MemoryCacheUtils mMemoryCacheUtils) {
this.mLocalCacheUtils = mLocalCacheUtils;
this.mMemoryCacheUtils = mMemoryCacheUtils;
}
/**
* 从网络下载图片
* @param ivPic
* @param url
*/
public void getBitmapFromNet(ImageView ivPic, String url) {
new BitmapTask().execute(ivPic, url); //启动 AsyncTask
}
class BitmapTask extends AsyncTask<Object, Void, Bitmap>
{
private ImageView ivPic;
private String url;
/**
* 耗时方法在此形成,子线程
*/
@Override
protected Bitmap doInBackground(Object... params) {
ivPic = (ImageView) params[0];
url = (String) params[1];
ivPic.setTag(url);
return downloadBitmap(url);
}
/**
* 更新进度,主线程
*/
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
/**
* 耗时方法结束后,执行该方法,主线程
*/
@Override
protected void onPostExecute(Bitmap result) {
if(result != null)
{
String bindUrl = (String) ivPic.getTag();
if(url.equals(bindUrl))
{
//确保图片设置了正确的ImageView
ivPic.setImageBitmap(result);
//将图片保存在本地
mLocalCacheUtils.setBitmapToLocal(url, result);
// 将图片保存在内存
mMemoryCacheUtils.setBitmapToMemory(url, result);
}
}
}
}
/**
* 下载图片
* @param url
* @return
*/
private Bitmap downloadBitmap(String url)
{
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn .setConnectTimeout(5000);
conn .setReadTimeout(5000);
conn .setRequestMethod("GET");
conn .connect();
int responseCode = conn .getResponseCode();
if(responseCode == 200)
{
InputStream inputStream = conn .getInputStream();
//图片压缩
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//宽高都压缩为原来的1/2
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeStream(inputStream,null, options);
return bitmap;
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
conn.disconnect();
}
return null;
}
}
从本地获取的类:
LocalCacheUtils.java
/**
* 本地缓存
* @author dream
*
*/
public class LocalCacheUtils {
public static final String CACHE_PATH = Environment.getExternalStorageDirectory().
getAbsolutePath() + "/beijingwisdom";
/**
* 从本地sdcard读图片
* @param url
*/
public Bitmap getBitmapFromLocal(String url)
{
try {
String fileName = MD5Encoder.encode(url);
File file = new File(CACHE_PATH,fileName);
if(file.exists())
{
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
return bitmap;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 向sdcard写图片
*/
public void setBitmapToLocal(String url,Bitmap bitmap)
{
try {
String fileName = MD5Encoder.encode(url);
File file = new File(CACHE_PATH,fileName);
File parentFile = file.getParentFile();
if(!parentFile.exists())
{
parentFile.mkdirs();
}
//将图片保存在本地
bitmap.compress(CompressFormat.JPEG
, 100, new FileOutputStream(parentFile) );
} catch (Exception e) {
e.printStackTrace();
}
}
}
从内存获取的类:
MemoryCacheUtils.java
/**
* 内存缓存
*
* @author dream
*
*/
public class MemoryCacheUtils {
// public HashMap<String, SoftReference<Bitmap>> mMemoryCache = new
// HashMap<String, SoftReference<Bitmap>>();
public LruCache<String, Bitmap> mMemoryCache;
public MemoryCacheUtils() {
long maxMemory = Runtime.getRuntime().maxMemory() / 8;// 模拟器默认16M
mMemoryCache = new LruCache<String, Bitmap>((int) (maxMemory)) {
@Override
protected int sizeOf(String key, Bitmap value) {
int byteCount = value.getRowBytes() * value.getHeight();
return byteCount;
}
};
}
/**
* 从内存读
*
* @param url
*/
public Bitmap getBitmapFromMemory(String url) {
// SoftReference<Bitmap> softReference = mMemoryCache.get(url);
// if(softReference != null)
// {
// Bitmap bitmap = softReference.get();
// return bitmap;
// }
return mMemoryCache.get(url);
}
/**
* 从设置内存读
*
* @param url
* @param bitmap
*/
public void setBitmapToMemory(String url, Bitmap bitmap) {
mMemoryCache.put(url, bitmap);
}
}
内存溢出问题:
Android默认每个app只能分配16M的内存,所以经常在内存中加载图片会发生内存溢出,我们来熟悉一下Java中的引用:
强引用:垃圾回收器不会回收,Java默认引用都是强引用
软引用:SoftReference 在内存不够时,Java垃圾回收会考虑回收
弱引用:WeakReference 在内存不够时,Java垃圾回收会优先回收
虚引用:PhantomReference 在内存不够时,Java垃圾回收会最优先回收
在Android2.3+,系统会优先将SoftReference的对象提前回收,即使内存够用,所以不再使用,所以这个我们也不能用了。
接下来介绍LruCache:
least recentlly use 最近最少未使用
会将内存控制在一定的大小内,超出最大值时会自动回收,这个最大值开发者自己定。
对于界面中可以缩放的图片我们也可以进行图片压缩。
InputStream inputStream = conn .getInputStream();
//图片压缩
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//宽高都压缩为原来的1/2
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeStream(inputStream,null, options);
return bitmap;