首页 > 编程 > Java > 正文

在Android的应用中实现网络图片异步加载的方法

2019-11-26 15:02:04
字体:
来源:转载
供稿:网友

前言
其实很幸运,入职一周之后就能跟着两个师兄做android开发,师兄都是大神,身为小白的我只能多多学习,多多努力。最近一段时间都忙的没机会总结,今天刚完成了android客户端图片异步加载的类,这里记录一下(ps:其实我这里都是参考网上开源实现)


原理
在ListView或者GridView中加载图片的原理基本都是一样的:

    先从内存缓存中获取,取到则返回,取不到进行下一步
    从文件缓存中获取,取到则返回并更新到内存缓存,取不到则进行进行下一步
    从网络上下载图片,并更新内存缓存和文件缓存


流程图如下:

2015731154609726.png (636×512)

同时,要注意线程的数量。一般在listview中加载图片,大家都是开启新的线程去加载,但是当快速滑动时,很容易造成OOM,因此需要控制线程数量。我们可以通过线程池控制线程的数量,具体线程池的大小还需要根据处理器的情况和业务情况自行判断

建立线程池的方法如下:

   

ExecutorService executorService = Executors.newFixedThreadPool(5); // 5是可变的 

文件缓存类

   

 import java.io.File;      import android.content.Context;      public class FileCache {     private static final String DIR_NAME = "your_dir";     private File cacheDir;        public FileCache(Context context) {       // Find the directory to save cached images       if (android.os.Environment.getExternalStorageState().equals(           android.os.Environment.MEDIA_MOUNTED)) {         cacheDir = new File(             android.os.Environment.getExternalStorageDirectory(),             DIR_NAME);       } else {         cacheDir = context.getCacheDir();       }          if (!cacheDir.exists()) {         cacheDir.mkdirs();       }     }        public File getFile(String url) {       // Identify images by url's hash code       String filename = String.valueOf(url.hashCode());          File f = new File(cacheDir, filename);          return f;     }        public void clear() {       File[] files = cacheDir.listFiles();       if (files == null) {         return;       } else {         for (File f : files) {           f.delete();         }       }     }   } 

内存缓存类
这里使用了软引用,Map<String, SoftReference<Bitmap>> cache,可以google一下软引用的机制,简单的说:实现了map,同时当内存紧张时可以被回收,不会造成内存泄露

   

 import java.lang.ref.SoftReference;   import java.util.Collections;   import java.util.LinkedHashMap;   import java.util.Map;      import android.graphics.Bitmap;      public class MemoryCache {     private Map<String, SoftReference<Bitmap>> cache = Collections         .synchronizedMap(new LinkedHashMap<String, SoftReference<Bitmap>>(             10, 1.5f, true));        public Bitmap get(String id) {       if (!cache.containsKey(id)) {         return null;       }          SoftReference<Bitmap> ref = cache.get(id);          return ref.get();     }        public void put(String id, Bitmap bitmap) {       cache.put(id, new SoftReference<Bitmap>(bitmap));     }        public void clear() {       cache.clear();     }   } 

图片加载类

  import java.io.File;   import java.io.FileInputStream;   import java.io.FileNotFoundException;   import java.io.FileOutputStream;   import java.io.InputStream;   import java.io.OutputStream;   import java.net.HttpURLConnection;   import java.net.URL;   import java.util.Collections;   import java.util.Map;   import java.util.WeakHashMap;   import java.util.concurrent.ExecutorService;   import java.util.concurrent.Executors;      import android.content.Context;   import android.graphics.Bitmap;   import android.graphics.BitmapFactory;   import android.os.Handler;   import android.widget.ImageView;      public class ImageLoader {     /**      * Network time out      */     private static final int TIME_OUT = 30000;     /**      * Default picture resource      */     private static final int DEFAULT_BG = R.drawable.plate_list_head_bg;        /**      * Thread pool number      */     private static final int THREAD_NUM = 5;        /**      * Memory image cache      */     MemoryCache memoryCache = new MemoryCache();        /**      * File image cache      */     FileCache fileCache;        /**      * Judge image view if it is reuse      */     private Map<ImageView, String> imageViews = Collections         .synchronizedMap(new WeakHashMap<ImageView, String>());        /**      * Thread pool      */     ExecutorService executorService;        /**      * Handler to display images in UI thread      */     Handler handler = new Handler();        public ImageLoader(Context context) {       fileCache = new FileCache(context);       executorService = Executors.newFixedThreadPool(THREAD_NUM);     }        public void disPlayImage(String url, ImageView imageView) {       imageViews.put(imageView, url);       Bitmap bitmap = memoryCache.get(url);       if (bitmap != null) {         // Display image from Memory cache         imageView.setImageBitmap(bitmap);       } else {         // Display image from File cache or Network         queuePhoto(url, imageView);       }     }        private void queuePhoto(String url, ImageView imageView) {       PhotoToLoad photoToLoad = new PhotoToLoad(url, imageView);       executorService.submit(new PhotosLoader(photoToLoad));     }        private Bitmap getBitmap(String url) {       File f = fileCache.getFile(url);          // From File cache       Bitmap bmp = decodeFile(f);       if (bmp != null) {         return bmp;       }          // From Network       try {         Bitmap bitmap = null;         URL imageUrl = new URL(url);         HttpURLConnection conn = (HttpURLConnection) imageUrl             .openConnection();         conn.setConnectTimeout(TIME_OUT);         conn.setReadTimeout(TIME_OUT);         conn.setInstanceFollowRedirects(true);         InputStream is = conn.getInputStream();         OutputStream os = new FileOutputStream(f);         copyStream(is, os);         os.close();         conn.disconnect();         bitmap = decodeFile(f);         return bitmap;       } catch (Throwable ex) {         if (ex instanceof OutOfMemoryError) {           clearCache();         }         return null;       }        }        private void copyStream(InputStream is, OutputStream os) {       int buffer_size = 1024;          try {         byte[] bytes = new byte[buffer_size];         while (true) {           int count = is.read(bytes, 0, buffer_size);           if (count == -1) {             break;           }           os.write(bytes, 0, count);         }          } catch (Exception e) {          }     }        private Bitmap decodeFile(File f) {       try {         // TODO:Compress image size         FileInputStream fileInputStream = new FileInputStream(f);         Bitmap bitmap = BitmapFactory.decodeStream(fileInputStream);         return bitmap;          } catch (FileNotFoundException e) {         return null;       }     }        private void clearCache() {       memoryCache.clear();       fileCache.clear();     }        /**      * Task for the queue      *      * @author zhengyi.wzy      *      */     private class PhotoToLoad {       public String url;       public ImageView imageView;          public PhotoToLoad(String url, ImageView imageView) {         this.url = url;         this.imageView = imageView;       }     }        /**      * Asynchronous to load picture      *      * @author zhengyi.wzy      *      */     class PhotosLoader implements Runnable {       PhotoToLoad photoToLoad;          public PhotosLoader(PhotoToLoad photoToLoad) {         this.photoToLoad = photoToLoad;       }          private boolean imageViewReused(PhotoToLoad photoToLoad) {         String tag = imageViews.get(photoToLoad.imageView);         if (tag == null || !tag.equals(photoToLoad.url)) {           return true;         }            return false;       }          @Override       public void run() {         // Abort current thread if Image View reused         if (imageViewReused(photoToLoad)) {           return;         }            Bitmap bitmap = getBitmap(photoToLoad.url);            // Update Memory         memoryCache.put(photoToLoad.url, bitmap);            if (imageViewReused(photoToLoad)) {           return;         }            // Don't change UI in children thread         BitmapDisplayer bd = new BitmapDisplayer(bitmap, photoToLoad);         handler.post(bd);       }          class BitmapDisplayer implements Runnable {         Bitmap bitmap;         PhotoToLoad photoToLoad;            public BitmapDisplayer(Bitmap bitmap, PhotoToLoad photoToLoad) {           this.bitmap = bitmap;           this.photoToLoad = photoToLoad;         }            @Override         public void run() {           if (imageViewReused(photoToLoad)) {             return;           }              if (bitmap != null) {             photoToLoad.imageView.setImageBitmap(bitmap);           } else {             photoToLoad.imageView.setImageResource(DEFAULT_BG);           }         }          }     }   } 

调用方法

  ImageLoader imageLoader = new ImageLoader(context);   imageLoader.disPlayImage(imageUrl, imageView); 

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表