Android 实现异步加载图片

摘要:
=null){StringfileName=url.hashCode()+".jpg";//如果缓存过就从缓存中取出数据if{SoftReferencesoftReference=imageCache.get;drawable=softReference.get();if(drawable!dir.exists()){booleanm=dir.mkdirs();}Filefile=newFile;if{Log.i;//如果文件存在则直接读取sdcarddrawable=readFromSdcard;}else{//file.createNewFile();Log.i;URLimageUrl=newURL;//写入sdcardif{saveImageFile;drawable=Drawable.createFromStream;}else{//直接从流读取drawable=Drawable.createFromStream;}}if(drawable!=null){//保存在缓存中imageCache.put;}}}catch{e.printStackTrace();}returndrawable;}/***saveimage*/privatevoidsaveImageFile{FileOutputStreamout=null;InputStreamin=null;try{file.deleteOnExit();out=newFileOutputStream;in=url.openStream();byte[]buf=newbyte[1024];intlen=-1;while((len=in.read(buf))!=null){try{in.close();}catch{e.printStackTrace();}}}}/***从sdcard中获取图片*/privateDrawablereadFromSdcardthrowsException{FileInputStreamin=newFileInputStream;returnDrawable.createFromStream;}@OverrideprotectedvoidonPostExecute{super.onPostExecute;Drawabledrawable=result;if(mImageView!

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

今天在做项目的时候,有一个实现异步加载图片的功能,虽然比较简单但还是记录一下吧.因为麦洛之前实现异步加载图片都是使用了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 实现异步加载图片》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇java中对list集合中的数据按照某一个属性进行分组蓝牙硬件交互数据传输Demo下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

调用钉钉接口发送消息

1.首先登陆钉钉开发者后台 https://ding-doc.dingtalk.com/ 2.选择H5微应用,创建应用 4.创建好之后,查看所建好的应用信息 其中AgentId,AppKey,AppSecret很重要,调用时需要用到 5.直接上代码看效果 1 string appkey = "dingv0cab6brl1ax6exd"; 2...

C# 实现opc ua服务器的远程连接(转)

原文转自:https://www.cnblogs.com/dathlin/p/7724834.html OPC UA简介 OPC是应用于工业通信的,在windows环境的下一种通讯技术,原有的通信技术难以满足日益复杂的环境,在可扩展性,安全性,跨平台性方面的不足日益明显,所以OPC基金会在几年前提出了面向未来的架构设计的OPC 统一架构,简称OPC UA...

Android随笔之——用shell脚本模拟用户按键、触摸操作

  之前写过两篇关于Android中模拟用户操作的博客(其实用一篇是转载的),现在就来讲讲用shell脚本来模拟用户按键操作。本次的目标是用shell脚本打开微信并在其搜索框中搜索相关内容。   本文的模拟功能主要是用adb的input命令来实现,如果你adb的环境变量配置正确的话,在cmd中输入 adb shell input 就可以看见input的用法...

android平台中编写jni模块的方法(3)

这篇文章来说说ndk的使用方法,其实主要是关于ndk的一些编译选项的研究和翻译(其实人家google的文档已经说的很清楚了)。偶选用的测试环境是 slackware 12.0 + android 1.5 r1 for linux + jdk 1.6.0_12,ndk选用的是android 1.5 ndk r1这个版本的(直接解压就行,免安装的)。1、从nd...

Android 解析后台返回为Json数据的简单例子

大家好,今天给大家分享下Android解析Json的例子,我这里自己安装了Tomcat,让自己电脑充当下服务器,最重要的是,返回结果自己可以随便修改。 首先看下Json的定义,以及它和XML的比较: JSON的定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了当今大部分...

JAVA之编码----&amp;gt;CSV在文本下是正常的,用EXCEL打开是乱码的问题

JAVA之编码---->CSV在文本下是正常的,用EXCEL打开是乱码的问题 在JAVA下输出文件流,保存成CSV(用UTF-8)文件,怎么处理用EXCEL下是乱码,但是在记事本等其他软件都是正常的,同时显示也是UTF-8的编码,经过测试发现如下结果: 1、EXCEL只能打开ANSI的编码,而ANSI需要当前操作系统是什么编码,就用什么编码。如中文...