麦洛开通博客以来,有一段时间没有更新博文了.主要是麦洛这段时间因项目开发实在太忙了.今天周六还在公司加班,苦逼程序猿都是这样生活的.

今天在做项目的时候,有一个实现异步加载图片的功能,虽然比较简单但还是记录一下吧.因为麦洛之前实现异步加载图片都是使用了AsynTask这个API,继续这个类,实现起来非常简单也很方便.在doInBackground()方法里实现下载逻辑.具体实现如下

实现逻辑是:先从内存中读取,如果内存中有这张图片,则直接使用;如果内存没有再到sdcard上读取,如果有则显示;如果sdcard上还没有则到网络上读取.内存中开启缓存是参考了网上的实现.麦洛在这里非常感谢喜欢分享的程序猿们.

public class ImageDownloader extends AsyncTask<String, Integer, Object> {

    private static final String TAG = "ImageDownloader";
// 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)
private Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
/**
* 显示图片的控件
*/
private ImageView mImageView; public ImageDownloader(ImageView image) {
mImageView = image;
} @Override
protected void onPreExecute() {
super.onPreExecute();
} @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 = imageCache.get(fileName);
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<Drawable>(drawable));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return drawable;
}
/**
* save image
*/
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();
}
}
}
} /**
* 从sdcard中获取图片
*/
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);
}
} @Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
} @Override
protected void onCancelled() {
super.onCancelled();
} }

使用时:

ImageDownloader loader = new ImageDownloader(imageView);
loader.execute(url);

其实这样的话,还有一些隐患的,就是说这个类实现还是有些问题的.比如每次都在imageView中设置网络上的图片时,其实是没有使用到这个类里面的内存缓存的,就是imageCache

Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
因为每次设置imageView的时候,都是new了一个ImageDownloader的对象.所以每个ImageDownloader对象里面都是独立的一个imageCache.
      另外,AsynTask也是一个线程.而每次使用都开一个线程来load 图片,对线程个数没有进行显示,毕竟线程数目还是有限制的.
所以麦洛今天发现了这个问题,于是参考了别人的实现,使用了线程池,实现逻辑也上面的代码一样,先从内存读取,如果没有到sdcard读取,如果还是没有,则是网络读取;实现没有使用AsynTask,具体代码如下:
/**
* 异步加载图片,并将图片设置到ImageView控件中
*/
public class ImageDownloader extends AsyncTask<String, Integer, Object> { private static final String TAG = "ImageDownloader";
// 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)
private Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
/**
* 显示图片的控件
*/
private ImageView mImageView; public ImageDownloader(ImageView image) {
mImageView = image;
} @Override
protected void onPreExecute() {
super.onPreExecute();
} @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 = imageCache.get(fileName);
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<Drawable>(drawable));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return drawable;
}
/**
* save image
*/
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();
}
}
}
} /**
* 从sdcard中获取图片
*/
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);
}
} @Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
} @Override
protected void onCancelled() {
super.onCancelled();
} }

这个ImageDownloader2的使用也很简单

public class ImageUtil {
/**
* image loader
*/
static ImageDownloader2 loader = null; /**
* load image
*/
public static void loadImage(String url,final ImageView imageView){
if(loader == null){
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的引用传入就可以了.

Android 实现异步加载图片的更多相关文章

  1. 又优化了一下 Android ListView 异步加载图片

    写这篇文章并不是教大家怎么样用listview异步加载图片,因为这样的文章在网上已经有很多了,比如这位仁兄写的就很好: http://www.iteye.com/topic/685986 我也是因为看 ...

  2. Android GridView异步加载图片和加载大量图片时出现Out Of Memory问题

    我们在使用GridView或者ListView时,通常会遇到两个棘手的问题: 1.每个Item获取的数据所用的时间太长会导致程序长时间黑屏,更甚会导致程序ANR,也就是Application No R ...

  3. android实现异步加载图片类

    其中牵涉到的关键知识点 1,回调机制,不过回调接口的实现方式有多种多样,可以是一个类继承该接口,也可以是作为一个方法参数: 可以参照自己的这篇博客: http://www.cnblogs.com/bo ...

  4. android listview 异步加载图片并防止错位

    网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertVie ...

  5. android ListView异步加载图片(双缓存)

    首先声明,参考博客地址:http://www.iteye.com/topic/685986 对于ListView,相信很多人都很熟悉,因为确实太常见了,所以,做的用户体验更好,就成了我们的追求... ...

  6. 转:Android ListView 异步加载图片

    http://www.iteye.com/topic/1118828 http://www.iteye.com/topic/1127914 这样做无疑是非常可取的方法,但是加载图片时仍然会感觉到轻微的 ...

  7. Android的ListView异步加载图片时,错位、重复、闪烁问题的分析及解决方法

    Android ListView异步加载图片错位.重复.闪烁分析以及解决方案,具体问题分析以及解决方案请看下文. 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图 ...

  8. listview异步加载图片并防止错位

    android listview 异步加载图片并防止错位 网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 conver ...

  9. 实例演示Android异步加载图片

    本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...

随机推荐

  1. Javascript中的this对象

    对于this的使用,我们最常遇到的主要有,在全局函数中,在对象方法中,call和apply时,闭包中,箭头函数中以及class中: 我们知道this对象是在运行时基于函数的执行环境绑定的,在调用函数之 ...

  2. jzoj5195. 【NOIP2017提高组模拟7.3】A(递推,打表)

    Description

  3. Linux安装redis PHP安装Redis扩展 and基本命令

    一.安装redis 用超级管理员身份运行: $ mkdir /usr/local/redis #redis安装目录 $ cd /usr/local/src #安装包下载目录 $ wget http:/ ...

  4. deepin系统无线网络卡死或者极慢的解决方案

    在初次安装deb或者fedara系列的桌面发行版的之后,经常会出现无线网络极慢甚至卡死的状况. 笔者在初次使用deepin系统的时候,也遇到同样的问题,很大程度上是由于没有安装对应的驱动. 下面给出对 ...

  5. navicat for MySQL连接本地数据库时报1045错误的解决方法

    navicat for MySQL 连接本地数据库出现1045错误 如下图: 说明连接mysql时数据库密码错误,需要修改密码后才可解决问题: 解决步骤如下: 1.首先打开命令行:开始->运行- ...

  6. javascript中几种this指向问题

    javascript中几种this指向问题   首先必须要说的是,this 永远指向函数运行时所在的对象,而不是函数被创建时所在的对象. (1).作为函数名调用   函数作为全局对象调用,this指向 ...

  7. JZOJ 5934. 列队

    Description         Sylvia是一个热爱学习的女孩子.        在平时的练习中,他总是能考到std以上的成绩,前段时间,他参加了一场练习赛,众所周知,机房是一个 的方阵.这 ...

  8. Spark-源码-Spark-StartAll Master Worler启动流程

    Spark start-all>> """Master启动流程""" Master类 class Master( host: S ...

  9. ctf题目writeup(5)

    2019.2.1 今天继续bugku的隐写杂项题:题目链接:https://ctf.bugku.com/challenges 1. 这道题下载后用wireshark打开...看了好久也没看出个所以然, ...

  10. sudo mount -o loop pm.img /mnt/floppy

    sudo mount -o loop pm.img /mnt/floppy 最近在学<一个操作系统的实现>,由于这本书比较老了,所以有一些对于软盘的操作指令现在用会出现一些错误,当我进行虚 ...