zoukankan      html  css  js  c++  java
  • 列表异步线程加载图片

    手机客户端以列表形式展示数据是非常常见的一种方式。然而列表中要显示图片(比如:头像)就要采用异步线程加载的方式,这样做是为了防止加载图片数据的时候,花费时间过长,阻塞UI线程,从而达到保持App的流畅性的目的。 

    下面我将分享 OSChina.NET Android版客户端的列表异步线程加载图片的方法: 

     

    图片缓存

    private static HashMap<String, SoftReference<Bitmap>> cache;  

    图片缓存是当有加载过相同的图片的时候,可以快速重复使用,比如同一个人的头像。

    图片控件集合

    private static Map<ImageView, String> imageViews;  

    图片控件集合是一个Map,记录当前ImageView控件对应的图片地址,用来防止异步线程加载图片时候ImageView控件显示的图片与实际图片地址对应的图片不符,出现错乱。

    线程池

    private static ExecutorService pool;  

    固定线程池里的并发线程数,可以防止用户在快速滑动列表的时候,不执行已经滑过去的加载线程。

    具体的初始化代码:

    static {  
            cache = new HashMap<String, SoftReference<Bitmap>>();  
            pool = Executors.newFixedThreadPool(5);  //固定线程池
            imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
        }


    接下来,我们来看看具体是如何加载图片的:

    public void loadBitmap(String url, ImageView imageView, Bitmap defaultBmp, int width, int height) {  
            imageViews.put(imageView, url);  
            Bitmap bitmap = getBitmapFromCache(url);  
       
            if (bitmap != null) {  
    	    //显示缓存图片
                imageView.setImageBitmap(bitmap);  
            } else {  
            	//加载SD卡中的图片缓存
            	String filename = FileUtils.getFileName(url);
            	String filepath = imageView.getContext().getFilesDir() + File.separator + filename;
        		File file = new File(filepath);
        		if(file.exists()){
    			//显示SD卡中的图片缓存
        			Bitmap bmp = ImageUtils.getBitmap(imageView.getContext(), filename);
            		imageView.setImageBitmap(bmp);
            	}else{
    			//线程加载网络图片
            		imageView.setImageBitmap(defaultBmp);
            		queueJob(url, imageView, width, height);
            	}
            }  
        }  

    上面的代码中,我们根据图片的url地址,先从图片缓存里面查找是否已缓存过,如果没有,再从SD卡的图片缓存文件中查找,如果再没有,最后才是加载网络图片。这才是以最快速的方式显示图片。

    下面,我将贴出完整的代码:

    /**
     * 异步线程加载图片工具类
     * @author  liux
     */
    public class BitmapManager {  
      
        private static HashMap<String, SoftReference<Bitmap>> cache;  
        private static ExecutorService pool;  
        private static Map<ImageView, String> imageViews;  
        private Bitmap defaultBmp;  
        
        static {  
            cache = new HashMap<String, SoftReference<Bitmap>>();  
            pool = Executors.newFixedThreadPool(5);  //固定线程池
            imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
        }  
        
        public BitmapManager(){}
        
        public BitmapManager(Bitmap def) {
        	this.defaultBmp = def;
        }
        
        /**
         * 设置默认图片
         * @param bmp
         */
        public void setDefaultBmp(Bitmap bmp) {  
        	defaultBmp = bmp;  
        }   
      
        /**
         * 加载图片
         * @param url
         * @param imageView
         */
        public void loadBitmap(String url, ImageView imageView) {  
        	loadBitmap(url, imageView, this.defaultBmp, 0, 0);
        }
    	
        /**
         * 加载图片-可设置加载失败后显示的默认图片
         * @param url
         * @param imageView
         * @param defaultBmp
         */
        public void loadBitmap(String url, ImageView imageView, Bitmap defaultBmp) {  
        	loadBitmap(url, imageView, defaultBmp, 0, 0);
        }
        
        /**
         * 加载图片-可指定显示图片的高宽
         * @param url
         * @param imageView
         * @param width
         * @param height
         */
        public void loadBitmap(String url, ImageView imageView, Bitmap defaultBmp, int width, int height) {  
            imageViews.put(imageView, url);  
            Bitmap bitmap = getBitmapFromCache(url);  
       
            if (bitmap != null) {  
    	    //显示缓存图片
                imageView.setImageBitmap(bitmap);  
            } else {  
                //加载SD卡中的图片缓存
                String filename = FileUtils.getFileName(url);
                String filepath = imageView.getContext().getFilesDir() + File.separator + filename;
        	    File file = new File(filepath);
        	    if(file.exists()){
    		//显示SD卡中的图片缓存
        		Bitmap bmp = ImageUtils.getBitmap(imageView.getContext(), filename);
            	imageView.setImageBitmap(bmp);
                }else{
    		//线程加载网络图片
            	imageView.setImageBitmap(defaultBmp);
            	queueJob(url, imageView, width, height);
                }
            }  
        }  
      
        /**
         * 从缓存中获取图片
         * @param url
         */
        public Bitmap getBitmapFromCache(String url) {  
        	Bitmap bitmap = null;
            if (cache.containsKey(url)) {  
                bitmap = cache.get(url).get();  
            }  
            return bitmap;  
        }  
        
        /**
         * 从网络中加载图片
         * @param url
         * @param imageView
         * @param width
         * @param height
         */
        public void queueJob(final String url, final ImageView imageView, final int width, final int height) {   
            final Handler handler = new Handler() {  
                public void handleMessage(Message msg) {  
                    String tag = imageViews.get(imageView);  
                    if (tag != null && tag.equals(url)) {  
                        if (msg.obj != null) {  
                            imageView.setImageBitmap((Bitmap) msg.obj);  
                            try {
                                //向SD卡中写入图片缓存
    			    ImageUtils.saveImage(imageView.getContext(), FileUtils.getFileName(url), (Bitmap) msg.obj);
    			} catch (IOException e) {
    			    e.printStackTrace();
    			}
                        } 
                    }  
                }  
            };  
      
            pool.execute(new Runnable() {   
                public void run() {  
                    Message message = Message.obtain();  
                    message.obj = downloadBitmap(url, width, height);  
                    handler.sendMessage(message);  
                }  
            });  
        } 
      
        /**
         * 下载图片-可指定显示图片的高宽
         * @param url
         * @param width
         * @param height
         */
        private Bitmap downloadBitmap(String url, int width, int height) {   
            Bitmap bitmap = null;
            try {
    	    //http加载图片
    	    bitmap = ApiClient.getNetBitmap(url);
    	    if(width > 0 && height > 0) {
    		//指定显示图片的高宽
    	        bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
    	    } 
    	    //放入缓存
    	    cache.put(url, new SoftReference<Bitmap>(bitmap));
    	} catch (Exception e) {
    	    e.printStackTrace();
    	}
            return bitmap;  
        }  
    }


    工具类使用 
    实例化时,可以设置默认的显示图片: 

    BitmapManager bmpManager = new BitmapManager(BitmapFactory.decodeResource(context.getResources(), R.drawable.loading));

    调用加载图片的方法:

    bmpManager.loadBitmap(imageURL, imageView);
  • 相关阅读:
    三层架构
    【Leetcode】Linked List Cycle II
    [Angular] @ContentChild with Directive ref
    [PostgreSQL] Use Foreign Keys to Ensure Data Integrity in Postgres
    [PostgreSQL] Ensure Uniqueness in Postgres
    [RxJS] Hot Observable, by .share()
    [RxJS] Implement pause and resume feature correctly through RxJS
    [RxJS] Replace zip with combineLatest when combining sources of data
    [RxJS] Use takeUntil instead of manually unsubscribing from Observables
    [RxJS] Convert RxJS Subjects to Observables
  • 原文地址:https://www.cnblogs.com/daocaowu/p/3172739.html
Copyright © 2011-2022 走看看