今天在做项目的时候,有一个实现异步加载图片的功能,虽然比较简单但还是记录一下吧.因为麦洛之前实现异步加载图片都是使用了AsynTask这个API,继续这个类,实现起来非常简单也很方便.在doInBackground()方法里实现下载逻辑.具体实现如下
实现逻辑是:先从内存中读取,如果内存中有这张图片,则直接使用;如果内存没有再到sdcard上读取,如果有则显示;如果sdcard上还没有则到网络上读取.内存中开启缓存是参考了网上的实现.麦洛在这里非常感谢喜欢分享的程序猿们.
public class ImageDownloader extends AsyncTask
private static final String TAG = “ImageDownloader”;
// 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)
private Map
/**
* 显示图片的控件
*/
private ImageView mImageView;
public ImageDownloader(ImageView image) {
mImageView = image;
}
@Override
protected Object doInBackground(String… params) {
// Log.i(“ImageDownloader”, “loading image…”);
String url = params[0];
Drawable drawable = null;
try {
if (!”".equals(url) && url != null) {
String fileName = url.hashCode()+”.jpg”;
// 如果缓存过就从缓存中取出数据
if (imageCache.containsKey(fileName)) {
SoftReference
drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}
File dir = new File(FileConstant.IMAGE_FILE_PATH);
if (!dir.exists()) {
boolean m = dir.mkdirs();
}
File file = new File(dir, fileName);
if (file.exists() && file.length() > 0) {
Log.i(TAG, “load image from sd card”);
// 如果文件存在则直接读取sdcard
drawable = readFromSdcard(file);
} else {
//file.createNewFile();
Log.i(TAG, “load image from network”);
URL imageUrl = new URL(url);
// 写入sdcard
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
saveImageFile(imageUrl, file);
drawable = Drawable.createFromStream(new FileInputStream(file), fileName);
}else{
//直接从流读取
drawable = Drawable.createFromStream(imageUrl.openStream(), fileName);
}
}
if(drawable!=null){
//保存在缓存中
imageCache.put(fileName, new SoftReference
}
}
} catch (Exception e) {
e.printStackTrace();
}
return drawable;
}
private void saveImageFile(URL url, File file) {
FileOutputStream out = null;
InputStream in = null;
try {
file.deleteOnExit();
out = new FileOutputStream(file);
in = url.openStream();
byte[] buf = new byte[1024];
int len = -1;
while((len = in.read(buf))!=-1){
out.write(buf, 0, len);
out.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(out!=null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private Drawable readFromSdcard(File file) throws Exception {
FileInputStream in = new FileInputStream(file);
return Drawable.createFromStream(in, file.getName());
}
@Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
Drawable drawable = (Drawable) result;
if (mImageView != null && drawable != null) {
mImageView.setBackgroundDrawable(drawable);
}
}
}
使用时:
public class ImageDownloader2 {
// 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)
private Map
// 固定五个线程来执行任务
private ExecutorService executorService = Executors.newFixedThreadPool(5);
private final Handler handler = new Handler();
public Drawable loadDrawable(final String imageUrl, final ImageCallback callback) {
Drawable drawable = null;
final String fileName = imageUrl.hashCode() + “.jpg”;
// 如果缓存过就从缓存中取出数据
if (imageCache.containsKey(fileName)) {
SoftReference
drawable = softReference.get();
if (drawable != null) {
callback.imageLoaded(drawable);
return drawable;
}
}
// 缓存中没有图像,则从网络或者文件中上取出数据,并将取出的数据缓存到内存中
executorService.submit(new LoadTask(fileName,imageUrl,callback));
return null;
}
/**
* 从网络或者sdcard加载图片
*/
class LoadTask implements Runnable {
String fileName;
String imageUrl;
Drawable drawable = null;
ImageCallback callback;
public LoadTask(String fileName,String imageUrl,ImageCallback callback){
this.fileName = fileName;
this.imageUrl = imageUrl;
this.callback = callback;
}
public void run() {
try {
// 从文件中读取
File dir = new File(FileConstant.IMAGE_FILE_PATH);
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir, fileName);
if (file.exists() && file.length() > 0) {
// 如果文件存在则直接读取sdcard
drawable = readFromSdcard(file);
} else {
drawable = loadImageFromUrl(imageUrl);
}
imageCache.put(fileName, new SoftReference
handler.post(new Runnable() {
public void run() {
callback.imageLoaded(drawable);
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private Drawable readFromSdcard(File file) {
try {
FileInputStream in = new FileInputStream(file);
return Drawable.createFromStream(in, file.getName());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
// 从网络上取数据方法
protected Drawable loadImageFromUrl(String imageUrl) {
try {
Drawable drawable = null;
URL url = new URL(imageUrl);
drawable = Drawable.createFromStream(url.openStream(), “image.jpg”);
return drawable;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 对外界开放的回调接口
*/
public interface ImageCallback {
// 注意 此方法是用来设置目标对象的图像资源
public void imageLoaded(Drawable imageDrawable);
}
}
这个ImageDownloader2的使用也很简单
public class ImageUtil {
static ImageDownloader2 loader = null;
public static void loadImage(String url,final ImageView imageView){
if(loader == null){
ImageDownloader loader = new ImageDownloader(imageView);
loader.execute(url);
loader = new ImageDownloader2();
}
loader.loadDrawable(url, new ImageCallback() {
@Override
public void imageLoaded(Drawable imageDrawable) {
if(imageDrawable!=null){
imageView.setBackgroundDrawable(imageDrawable);
}
}
});
}
}
每次在使用是需要调用ImageUtil.loadImage(url,imageView)将图片url已经需要显示图片的控件ImageView的引用传入就可以了.