使用LruCache和DiskLruCache来下载图片
LruCache是一个非常好用的图片缓存工具:
主要做法是:滑动图片时将图片的bitmap缓存在LruCache<String, Bitmap>中,退出程序后将图片缓存进文件中。採用DiskLruCache mDiskLruCache
所以我们必须设置一个图片缓存的地址:
public void setImageCache(){
String strPath = null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File sdFile = Environment.getExternalStorageDirectory();
strPath = sdFile.getAbsolutePath() + "/pic/";
File cacheFile = new File(strPath);
if(!cacheFile.exists()){
cacheFile.mkdir();
}
}
else{
String strCacheDir = this.getCacheDir().getAbsolutePath();
strPath = strCacheDir + "/pic/";
}
setCachePath(strPath);
}
private void setCachePath(String strPicCachePath){
if(TextUtils.isEmpty(strPicCachePath)){
return;
}
m_strPicCachePath = strPicCachePath;
File cacheFile = new File(strPicCachePath);
if(!cacheFile.exists()){
cacheFile.mkdir();
}
}
public String getCacheBmpPath(String strUrl){
if(TextUtils.isEmpty(m_strPicCachePath) || TextUtils.isEmpty(strUrl)){
return "";
}
return m_strPicCachePath + StringUtil.MD5Encode(strUrl) + mFileExName;//".bmp";
}
然后写List的adapter:
private class ListAdapter extends BaseAdapter implements OnScrollListener {
protected List<ShopData> items = new ArrayList<ShopData>();
protected static final int FETCH_IMAGE_MSG = 1;
private LruCache<String, Bitmap> mMemoryCache;
protected HashSet<ImageView> mItemsMissingImages = new HashSet<ImageView>();
protected ImageLoaderHandler mHandler;
protected ImageLoader mImageFetcher;
public static final int TIMEOUT = 30000;//超时时间30秒
private DiskLruCache mDiskLruCache;
public ListAdapter() {
super();
mHandler = new ImageLoaderHandler();
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int mCacheSize = maxMemory / 8;
// 给LruCache分配1/8 4M
mMemoryCache = new LruCache<String, Bitmap>(mCacheSize) {
// 必须重写此方法,来測量Bitmap的大小
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
try {
mDiskLruCache = DiskLruCache
.open(new File(m_strPicCachePath), getAppVersion(MainActivityTest.this), 1, 10 * 1024 * 1024);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 将缓存记录同步到journal文件里。
*/
public void fluchCache() {
if (mDiskLruCache != null) {
try {
mDiskLruCache.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ShopDataTag tag = new ShopDataTag();
if (convertView == null) {
convertView = mInflater.inflate(R.layout.listitem, null);
tag.name = (TextView) convertView.findViewById(R.id.name);
tag.shopInfo = (TextView) convertView.findViewById(R.id.info);
tag.icon = (ImageView) convertView.findViewById(R.id.image_icon);
convertView.setTag(tag);
} else {
tag = (ShopDataTag) convertView.getTag();
}
TextView name = tag.name;
TextView info = tag.shopInfo;
ImageView imageView = tag.icon;
ShopData data = items.get(position);
name.setText(data.name);
info.setText(data.info);
imageView.setTag(data.url);
setContactPhoto(data.url, imageView);
return convertView;
}
protected void setContactPhoto(String url,ImageView viewToUse) {
if(TextUtils.isEmpty(url)) {
viewToUse.setImageResource(R.drawable.avatar);
}else{
//先看mMemoryCache里能不能得到bitmap
Bitmap bitmap = mMemoryCache.get(url);
if (bitmap != null) {
viewToUse.setImageBitmap(bitmap);
} else {
Snapshot snapShot = null;
FileDescriptor fileDescriptor = null;
FileInputStream fileInputStream = null;
try {
//由于mDiskLruCache会把key作为文件名称。所以把url通过md5转换为key
final String key = hashKeyForDisk(url);
snapShot = mDiskLruCache.get(key);
//假设snapShot为空,就是没找到相应的文件
if (snapShot == null) {
//这里去下载
fetchImage(viewToUse);
}else{
fileInputStream = (FileInputStream) snapShot.getInputStream(0);
fileDescriptor = fileInputStream.getFD();
if (fileDescriptor != null) {
bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
}
//假设解析文件成bitmap失败。又一次下载
if(!TextUtils.isEmpty(url) && bitmap != null){
mMemoryCache.put(url, bitmap);
viewToUse.setImageBitmap(bitmap);
}else{
fetchImage(viewToUse);
}
}
}catch(IOException ex) {
ex.printStackTrace();
}finally{
if (fileDescriptor == null && fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
}
}
}
}
}
}
private void fetchImage(ImageView viewToUse) {
viewToUse.setImageResource(R.drawable.avatar);
mItemsMissingImages.add(viewToUse);
if (mScrollState != OnScrollListener.SCROLL_STATE_FLING) {
sendFetchImageMessage(viewToUse);
}
}
public String <strong>hashKeyForDisk</strong>(String key) { 将key转换为md5文件
return StringUtil.MD5Encode(key);
}
// image downloader
private class ImageLoaderHandler extends Handler {
@Override
public void handleMessage(Message message) {
if (isFinishing()) {
return;
}
switch (message.what) {
case FETCH_IMAGE_MSG: {
final ImageView imageView = (ImageView) message.obj;
if (imageView == null) {
break;
}
final String url = (String) imageView.getTag();
if (TextUtils.isEmpty(url)) {
break;
}
Bitmap map = getBitmapFromMemCache(url);
if (map == null) {
break;
}
synchronized (imageView) {
final String myUrl = (String) imageView.getTag();
if (TextUtils.equals(url, myUrl)) {
imageView.setImageBitmap(map);
mItemsMissingImages.remove(imageView);
} else {
}
}
break;
}
}
}
public void clearImageFecthing() {
removeMessages(FETCH_IMAGE_MSG);
}
}
private class ImageLoader implements Runnable {
String url;
private ImageView mImageView;
public ImageLoader(String url, ImageView imageView) {
this.url = url;
this.mImageView = imageView;
}
public void run() {
if (isFinishing()) {
return;
}
if (Thread.interrupted()) {
return;
}
FileDescriptor fileDescriptor = null;
FileInputStream fileInputStream = null;
Snapshot snapShot = null;
try {
final String key = hashKeyForDisk(url);
snapShot = mDiskLruCache.get(key);
if (snapShot == null) {
// 假设没有找到相应的缓存,则准备从网络上请求数据。并写入缓存
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(0);
boolean flag = downloadImage(url, outputStream);
if (flag) {
editor.commit();
} else {
editor.abort();
}
}
// 缓存被写入后,再次查找key相应的缓存
snapShot = mDiskLruCache.get(key);
}
//这里应该删除相应的文件
if (snapShot != null) {
fileInputStream = (FileInputStream) snapShot.getInputStream(0);
fileDescriptor = fileInputStream.getFD();
}
// 将缓存数据解析成Bitmap对象
Bitmap bitmap = null;
if (fileDescriptor != null) {
bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
}
if (bitmap != null) {
// 将Bitmap对象加入到内存缓存其中
mMemoryCache.put(url, bitmap);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileDescriptor == null && fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
}
}
}
if (Thread.interrupted()) {
return;
}
Message msg = new Message();
msg.what = FETCH_IMAGE_MSG;
msg.obj = mImageView;
mHandler.sendMessage(msg);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
public boolean downloadImage(String strUrl,OutputStream fos) {
URL getUrl = null;
Bitmap bitmap = null;
BufferedOutputStream out = null;
BufferedInputStream in = null;
try {
getUrl = new URL(strUrl);
} catch (MalformedURLException ex) {
Log.e("HttpUtil", "get MalformedURL", ex);
return false;
}
InputStream input = null;
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection)getUrl.openConnection();
conn.setConnectTimeout(TIMEOUT);
conn.setReadTimeout(TIMEOUT);
conn.setDoInput(true);
conn.connect();
input = conn.getInputStream();
in = new BufferedInputStream(input, 8 * 1024);
out = new BufferedOutputStream(fos, 8 * 1024);
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
return true;
} catch (Exception ex) {
Log.e("HttpUtil", "downloadImage", ex);
} catch(OutOfMemoryError ex){
ex.printStackTrace();
} finally {
try {
if(out != null){
out.close();
out = null;
}
if (in != null){
in.close();
in = null;
}
if (conn != null){
conn.disconnect();
conn = null;
}
} catch (Exception ex) {
Log.e("HttpUtil", "downloadImage finally", ex);
}
}
return false;
}
private boolean getResponse(InputStream input, OutputStream os, byte[] data) throws IOException{
if(input == null || os == null || data == null){
return false;
}
int i = 0;
while( (i = input.read(data)) != -1){
os.write(data, 0, i);
os.flush();
}
os.flush();
return true;
}
private void processMissingImageItems(AbsListView view) {
for (ImageView iv : mItemsMissingImages) {
sendFetchImageMessage(iv);
}
}
protected void sendFetchImageMessage(ImageView view) {
final String url = (String) view.getTag();
if (TextUtils.isEmpty(url)) {
return;
}
mImageFetcher = new ImageLoader(url, view);
synchronized (MainActivityTest.this) {
if (sImageFetchThreadPool == null) {
sImageFetchThreadPool = Executors.newFixedThreadPool(3);
}
sImageFetchThreadPool.execute(mImageFetcher);
}
}
public void clearImageFetching() {
synchronized (MainActivityTest.this) {
if (sImageFetchThreadPool != null) {
sImageFetchThreadPool.shutdownNow();
sImageFetchThreadPool = null;
}
}
mHandler.clearImageFecthing();
}
public void clearMessages() {
if (mHandler != null) {
try {
mHandler.removeCallbacksAndMessages(null);
} catch (java.lang.Throwable th) {
}
mHandler = null;
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
mScrollState = scrollState;
if (scrollState == OnScrollListener.SCROLL_STATE_FLING) {
clearImageFetching();
} else {
processMissingImageItems(view);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
}
private class ShopDataTag {
TextView name;
TextView shopInfo;
ImageView icon;
}
效果图:
使用LruCache和DiskLruCache来下载图片的更多相关文章
- 安卓开发笔记——关于图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...
- 综合使用LruCache和DiskLruCache 缓存图片
Activity public class MainActivity extends Activity { private GridView mPhotoWall; private P ...
- Android Volley框架的使用(四)图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...
- Android照片墙完整版,的完美结合LruCache和DiskLruCache
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/34093441 在上一篇文章其中,我们学习了DiskLruCache的概念和基本使用 ...
- 使用lrucache和diskLrucache实现照片墙
其实,在真正的项目实战当中如果仅仅是使用硬盘缓存的话,程序是有明显短板的.而如果只使用内存缓存的话,程序当然也会有很大的缺陷.因此,一个优秀的程序必然会将内存缓存和硬盘缓存结合到一起使用,那么本篇文章 ...
- Android照片墙完整版,完美结合LruCache和DiskLruCache
转载地址:http://blog.csdn.net/guolin_blog/article/details/34093441#comments 在上一篇文章当中,我们学习了DiskLruCache的概 ...
- 网络图片的获取以及二级缓存策略(Volley框架+内存LruCache+磁盘DiskLruCache)
在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...
- C++根据图片url下载图片
需要使用到URLDownloadToFile()函数,该函数在头文件<urlmon.h>中声明. URLDownloadToFile()函数的定义如下: HRESULT URLDownlo ...
- .net 已知图片的网络路径,通过浏览器下载图片
没什么技术含量,主要留给自己查找方便: 如题,知道图片的完整网络路径的情况下,在浏览器中下载图片的实现: 下面这个方法实现的是把图片读取为byte数组: private byte[] GetImage ...
随机推荐
- 关于.net core 在docker中监听地址设置踩坑记
1.今天在做docker容器的时候发现如果将.net core 内部监听地址设置为localhost:8888. 2.在docker build -p 6444:8888 运行容器后,外部通过6444 ...
- jquery-ui日期时间控件实现
日期控件和时间控件为独立控件,日期时间控件要同一时候导入日期控件和时间控件的js,然后在日期控件加入时间控件显示參数,没有导入时间控件js.日期控件函数设置的时间控件參将包错 日期控件官网网址:htt ...
- 【HDU-4614】Vases and Flowers(线段树双查询)
11946317 2014-10-23 09:08:28 Accepted 4614 437MS 2348K rid=11946317" target="_blank" ...
- ASCII中的控制字符含义
十进制 十六进制 控制字符 转义字符 说明 Ctrl + 下列字母 0 00 NUL \0 Null character(空字符) @ 1 01 SOH Start of Header(标题開始) ...
- Innosetup
卸载的同时删除日志,卸载的时候判断程序是否正在运行,regsvr32 1.卸载程序的时候如何判断程序是否正在运行 http://bbs.csdn.net/topics/370097914 2.强制删除 ...
- Wow C++11
什么是C++11? 一句话C++11是最新的C++标准,在2011年发布,所以叫C++11.在新的标准出现前,我们一直在用的是C++98,可想而知这份标准是1998年发布的,之后再2003年最过小的修 ...
- Golang 学习笔记 目录总结
- 基础: 下载安装 声明变量的方法 数据的三种基础类型:bool,数字,string 数据类型:数组和切片 数据类型:Maps 条件判断以及循环 函数 包管理 package 指针 结构体 - 初步 ...
- Idea的一些调试技巧及设置todo
程序员的工作内容,除了大部分时间写代码之外,因为有不少的时间是用在调试代码上.甚至说不是在调试代码,就是即将调试代码. :) 今天我们来谈谈调试代码的一些技巧,在使用IDE提供的debugger时一些 ...
- C#篇(三)——函数传参之引用类型和值类型
首先应该认清楚在C#中只有两种类型: 1.引用类型(任何称为"类"的类型) 2.值类型(结构或枚举) 先来认识一下引用类型和值类型的区别: 函数传参之引用类型: 1.先来一个简单的 ...
- C#篇(一)——字段与属性
字段和属性有什么区别? class Student { private int age; public int Age { get { return age; } set { age = value; ...