这部分代码通过在sd卡中保存图片文件实现文件方式的缓存,并且在加载时将图片load到内存中,显示时直接使用内存中已有内容。具体代码如下:
package com.example.xxx;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ImageView;
import com.example.xxx.conf.Configuration;
@SuppressLint("HandlerLeak")
public class ImageLoader {
// 链接地址字符串
private String urlString = null;
// 需要绘制的ImageView
private ImageView imageView = null;
// 保存urlString对应的Bitmap
private Map<String, Bitmap> imageMap = new HashMap<String, Bitmap>();
private final static int UPDATE_IMAGEVIEW = 1;
private WorkingThread workingThread = null;
// 处理刷新主界面的handler
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_IMAGEVIEW:
displayImage();
break;
default:
super.handleMessage(msg);
break;
}
}
};
/**
* 后台线程,用于下载网络图片
* @author sam
*
*/
class WorkingThread extends Thread {
// 缓冲区大小
private static final int BUF_SIZE = 4096;
// 临时文件后缀名
private final static String SUFFIX = ".tmp";
@Override
public void run() {
try {
HttpURLConnection conn = (HttpURLConnection) new URL(urlString)
.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is = conn.getInputStream();
// 缓存文件名
String cacheFileName = ImageLoader.getCacheFileName(urlString);
// 临时文件名
String tmpFileName = cacheFileName + SUFFIX;
OutputStream os = new FileOutputStream(tmpFileName);
byte[] buffer = new byte[BUF_SIZE];
int size = 0;
while ((size = is.read(buffer)) > 0) {
os.write(buffer, 0, size);
}
os.close();
// 写入文件结束,改名
File tmpFile = new File(tmpFileName);
if (!tmpFile.renameTo(new File(cacheFileName)))
Log.e("ImageLoader", "Failed to rename tmpFile.");
// 通知主线程完成更新
Message msg = ImageLoader.this.handler.obtainMessage(UPDATE_IMAGEVIEW);
handler.sendMessage(msg);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
super.run();
}
}
public ImageLoader(String urlString, ImageView imageView) {
this.urlString = urlString;
this.imageView = imageView;
}
/**
* 获得缓存文件名
*
* @param urlString
* @return
*/
public static String getCacheFileName(String urlString) {
try {
URL url = new URL(urlString);
String relativeFilename = url.getFile();
String[] splitString = relativeFilename.split(File.separator);
if (splitString.length > 0)
return Configuration.CACHE_PATH
+ splitString[splitString.length - 1];
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
/**
* 在ImageView中显示网络图片
* @param urlString
* @param imageView
*/
public void displayImage() {
String cacheFileName = getCacheFileName(urlString);
File cacheFile = new File(cacheFileName);
// 如果已经缓存过图片,直接显示
if (imageMap.get(urlString) != null) {
imageView.setImageBitmap(imageMap.get(urlString));
} else {
// 如果文件已经存在,加载到内存中并显示
if (cacheFile.exists()) {
Bitmap bm = decodeFile(cacheFile);
imageMap.put(urlString, bm);
imageView.setImageBitmap(bm);
} else {
// 文件不存在,启动线程后台下载图片
downloadPicture();
// 暂时显示默认图片
imageView.setImageResource(Configuration.DEFAULT_IMAGE);
}
}
}
/**
* 启动线程下载图片
*/
private void downloadPicture() {
workingThread = new WorkingThread();
workingThread.start();
}
/**
* 加载图片为Bitmap
* @param f
* @return
*/
private Bitmap decodeFile(File f) {
try {
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
}