zoukankan      html  css  js  c++  java
  • Android 实现异步加载图片

    麦洛原文连接http://miloisbadboy.com/archives/51

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

    今天在做项目的时候,有一个实现异步加载图片的功能,虽然比较简单但还是记录一下吧.因为麦洛之前实现异步加载图片都是使用了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的引用传入就可以了.

     

     

     

  • 相关阅读:
    浏览器内置对象及其方法
    Leetcode | Path Sum I && II
    Leetcode | 3Sum
    算法分析之渐近符号
    Leetcode | Two Sum
    Leetcode | Wildcard Matching
    LeetCode | Regular Expression Matching
    Leetcode | Subsets I & II
    Leetcode | Populating Next Right Pointers in Each Node I & II
    爱是恒久忍耐,又有恩慈
  • 原文地址:https://www.cnblogs.com/angrycode/p/2613675.html
Copyright © 2011-2022 走看看