当前位置: 代码迷 >> Android >> Android异步加载图片详解之形式一(2)
  详细解决方案

Android异步加载图片详解之形式一(2)

热度:55   发布时间:2016-05-01 12:44:55.0
Android异步加载图片详解之方式一(2)

FileCache.java如下:

package cn.loadImages;import java.io.File;import android.content.Context;import android.net.Uri;import android.os.Environment;public class FileCache {    private File fileCacheDir;    public FileCache(Context context){        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){        	fileCacheDir=new File(Environment.getExternalStorageDirectory(),"idealLV001");        }        else{        	 //context.getCacheDir();        	 //获取缓存文件所在的目录        	 fileCacheDir=context.getCacheDir();        }                if(!fileCacheDir.exists()){        	 fileCacheDir.mkdirs();        }               }        public File getImageFile(String url){        //String filename=String.valueOf(url.hashCode());        //String filename = URLEncoder.encode(url);        Uri uri=Uri.parse(url);        String fileName=uri.getLastPathSegment();        File file= new File(fileCacheDir, fileName);        return file;    }    	public void clear() {		File[] files = fileCacheDir.listFiles();		if (files == null) {			return;		}		for (File file : files) {			file.delete();		}	}}


MemoryCache.java如下:

package cn.loadImages;import java.lang.ref.SoftReference;import java.util.Collections;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.Map;import java.util.Map.Entry;import java.util.concurrent.ConcurrentHashMap;import android.graphics.Bitmap;import android.util.Log;public class MemoryCache {    private static final String TAG = "xx";    public static HashMap<String, Integer> bitmapsSizeHashMap;    //1 建立一级缓存    //  注意:利用了Collections.synchronizedMap使其变为一个同步的map    private Map<String, Bitmap> hardBitmapCacheHashMap=    Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(10,1.5f,true));    //2 建立二级缓存    private final static ConcurrentHashMap<String, SoftReference<Bitmap>> 	softBitmapCacheHashMap = new ConcurrentHashMap<String, SoftReference<Bitmap>>(20);    //一级缓存分配的总大小    private long allocatedMemoryMaxSize=0;    //一级缓存已使用的大小    private long nowTotalUsedMemorySize=0;        public MemoryCache(){        //use 10% of available heap size        setAllocatedMemoryMaxSize(Runtime.getRuntime().maxMemory()/10);//85        bitmapsSizeHashMap=new HashMap<String, Integer>();    }        public void setAllocatedMemoryMaxSize(long allocatedMemoryMaxSize){        this.allocatedMemoryMaxSize=allocatedMemoryMaxSize;        Log.i(TAG, "allocatedMemoryMaxSize="+allocatedMemoryMaxSize/1024/1024+"MB");    }	public Bitmap getBitmapFromMemory(String url) {		try {			//1 从一级缓存中查找图片			Bitmap bitmap = hardBitmapCacheHashMap.get(url);			if (bitmap != null) {				// 既然现在要得到此图片,则该图片为最近被使用				// 即在所有的对象中为最新的对象.				// 所以先将该对象从hardBitmapCacheHashMap中移除				// 再将其插入到hardBitmapCacheHashMap的最前面				hardBitmapCacheHashMap.remove(url);				hardBitmapCacheHashMap.put(url, bitmap);				return bitmap;			}            //2 从二级缓存中查找图片			// 因为:若在sHardBitmapCache中没有,那么可能是因为该对象太陈旧			// 且sHardBitmapCache容量已达上限,所以将其存入softBitmapCacheHashMap			// 所以尝试从softBitmapCacheHashMap中获取对象			 System.out.println("88 get方法中从SoftReference获取");			 System.out.println("88 get方法中从SoftReference获取的url="+url);			SoftReference<Bitmap> bitmapReference = softBitmapCacheHashMap.get(url);			if (bitmapReference != null) {				Bitmap bp = bitmapReference.get();				if (bp != null) {					return bp;				} else {					// SoftReference已被GC回收					softBitmapCacheHashMap.remove(url);				}			}			return null;		} catch (NullPointerException ex) {			ex.printStackTrace();			return null;		}	}    public void putBitmapToMemory(String url, Bitmap bitmap){    	 try{             if(!hardBitmapCacheHashMap.containsKey(url)){            	 nowTotalUsedMemorySize+=getBitmapSizeInBytes(bitmap,url);                 System.out.println("88 put方法中 nowTotalUsedMemorySize="+nowTotalUsedMemorySize);                 checkMemorySizeStatus();                 hardBitmapCacheHashMap.put(url, bitmap);             }                      }catch(Throwable th){             th.printStackTrace();         }    }            //检查一级缓存的使用情况    //若一级缓存已达上限,则将该缓存中组后一个元素放入二级缓存softBitmapCacheHashMap中    //再将其充一级缓存hardBitmapCacheHashMap中删除    private void checkMemorySizeStatus() {    	int hardBitmapCacheHashMapSize=hardBitmapCacheHashMap.size();    	int count=0;    	 System.out.println("88 checkSizeStatus方法中 nowTotalUsedMemorySize="+nowTotalUsedMemorySize);    	 System.out.println("88 checkSizeStatus方法中 memoryMaxSize="+allocatedMemoryMaxSize);    	        if(nowTotalUsedMemorySize>=allocatedMemoryMaxSize){        	System.out.println("88 checkSizeStatus方法中  满足nowTotalUsedMemorySize>=memoryMaxSize");        	System.out.println("88 checkSizeStatus方法中  hardBitmapCacheHashMap.size()="+hardBitmapCacheHashMap.size());            Iterator<Entry<String, Bitmap>> iter=hardBitmapCacheHashMap.entrySet().iterator();            //least recently accessed item will be the first one iterated            while(iter.hasNext()){            	count++;            	Entry<String, Bitmap> entry=iter.next();            	if (count==hardBitmapCacheHashMapSize) {            		 System.out.println("88 checkSizeStatus方法中 count="+count);            		 System.out.println("88 checkSizeStatus方法中 memoryMaxSize="+allocatedMemoryMaxSize);            		 System.out.println("88 checkSizeStatus方法中 删除前 nowTotalUsedMemorySize="+nowTotalUsedMemorySize);            		 nowTotalUsedMemorySize-=getBitmapSizeInBytes(entry.getValue(),entry.getKey());            		 //1将最后一个元素放到softBitmapCacheHashMap中            		 softBitmapCacheHashMap.put(entry.getKey(),new SoftReference<Bitmap>(entry.getValue()));            		  System.out.println("88 checkSizeStatus方法中放到SoftReference的url="+entry.getKey());            		  System.out.println("88 checkSizeStatus方法中放入SoftReference后softBitmapCacheHashMap.size()="+softBitmapCacheHashMap.size());                     //2 删除最后的这一个元素                     iter.remove();                     //3 从bitmapsSizeHashMap中删除该元素                     bitmapsSizeHashMap.remove(entry.getKey());                     System.out.println("88 checkSizeStatus方法中 删除后 hardBitmapCacheHashMap.size()="+hardBitmapCacheHashMap.size());                     System.out.println("88 checkSizeStatus方法中 删除后 softBitmapCacheHashMap.size()="+softBitmapCacheHashMap.size());                                          System.out.println("88 checkSizeStatus方法中 删除后 nowTotalUsedMemorySize="+nowTotalUsedMemorySize);                     System.out.println("88 checkSizeStatus方法中 删除后 memoryMaxSize="+allocatedMemoryMaxSize);            	}                }        }        if(nowTotalUsedMemorySize>=allocatedMemoryMaxSize){            checkMemorySizeStatus();        }           }    public void clear() {        try{            hardBitmapCacheHashMap.clear();            softBitmapCacheHashMap.clear();            bitmapsSizeHashMap.clear();            nowTotalUsedMemorySize=0;        }catch(NullPointerException ex){            ex.printStackTrace();        }    }    //得到Bitmap的大小    long getBitmapSizeInBytes(Bitmap bitmap,String url) {        if(bitmap==null){        	 return 0;        }          int bitmapSize=bitmapsSizeHashMap.get(url);         return bitmapSize;        //return bitmap.getRowBytes() * bitmap.getHeight();    }       }


ImageLoader.java如下:

package cn.loadImages;import java.io.File;import java.io.FileInputStream;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.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.widget.ImageView;import cn.ideallistview.R;public class ImageLoader {    MemoryCache memoryCache=new MemoryCache();    FileCache fileCache;    private boolean isgetBitmapThumbnail=false;    private final int REQUIRED_BITMAP_WIDTH=50;    private final int REQUIRED_BITMAP_HEIGHT=50;    private final int REQUIRED_BITMAP_MAXNUMOFPIXELS=200*200;    //参见文档:    //WeakHashMap像大多数集合类一样,是不同步的.    //可使用 Collections.synchronizedMap方法来构造同步的WeakHashMap    private Map<ImageView, String> imageViewsWeakHashMap=    Collections.synchronizedMap(new WeakHashMap<ImageView, String>());    ExecutorService executorService;     //默认的图片    final int defaultImageId=R.drawable.stub;    public ImageLoader(Context context){        fileCache=new FileCache(context);        //创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程        executorService=Executors.newFixedThreadPool(5);    }       //显示网络图片    public void displayImage(String url, ImageView imageView){    	//1 将imageView和其对应的url放入imageViewsWeakHashMap中        imageViewsWeakHashMap.put(imageView, url);        //2 试图从内存中得到图片        Bitmap bitmap=memoryCache.getBitmapFromMemory(url);        if(bitmap!=null){        	 imageView.setImageBitmap(bitmap);        }       //3 不在内存中,则从SD卡和网络上获取        else{            taskQueueForImages(url, imageView);            imageView.setImageResource(defaultImageId);        }    }            private void taskQueueForImages(String url, ImageView imageView){        WillLoadedImageBean willLoadedImageBean=new WillLoadedImageBean(url, imageView);        //提交一个 Runnable任务用于执行,并返回一个表示该任务的 Future        executorService.submit(new LoaderImagesRunnable(willLoadedImageBean));    }        //该线程在线程池中运行    class LoaderImagesRunnable implements Runnable {        WillLoadedImageBean willLoadedImageBean;        LoaderImagesRunnable(WillLoadedImageBean willLoadedImageBean){            this.willLoadedImageBean=willLoadedImageBean;        }                @Override        public void run() {            try{                if(isImageViewReused(willLoadedImageBean)){                	 return;                }                //依据图片Url获得其对应的Bitmap                //1 从SDCard中寻找                //2 若不在SDCard中,则从网络下载,且将图片存至SDCard中                //3 将SDCard中图片返回至此                Bitmap bitmap=getBitmapByUrl(willLoadedImageBean.url);                //4 将图片存至memoryCache中                memoryCache.putBitmapToMemory(willLoadedImageBean.url, bitmap);                if(isImageViewReused(willLoadedImageBean)){                	 return;                }                //5 将Bitmap在UI中显示                BitmapDisplayerRunnableInUIThread bitmapDisplayerRunnable                =new BitmapDisplayerRunnableInUIThread(bitmap, willLoadedImageBean);                Activity activity=(Activity)willLoadedImageBean.imageView.getContext();                activity.runOnUiThread(bitmapDisplayerRunnable);            }catch(Throwable th){                th.printStackTrace();            }        }    }        //通过Url得到其对应的Bitmap    private Bitmap getBitmapByUrl(String url)     {      	//1 从SD卡中获取        File file=fileCache.getImageFile(url);        Bitmap bitmap = getBitmapFromSDCardFile(file);        if(bitmap!=null){        	return bitmap;        }else{        	//2 若不存在SD卡中,则从网络下载并存至SD卡的File文件中        	 bitmap=getBitmapFromNetWork(url,file);        	 if (bitmap!=null) {				return bitmap;			}        }		return null;    }      	private Bitmap getBitmapFromSDCardFile(File file) {		if (!isgetBitmapThumbnail) {			try {				FileInputStream inputStream = new FileInputStream(file);				Bitmap bitmap = BitmapFactory.decodeStream(inputStream);				inputStream.close();				return bitmap;			} catch (Exception e) {				e.printStackTrace();			}		} else {			try {			String filePath=file.getAbsolutePath();			int minSideLength=Math.min(REQUIRED_BITMAP_HEIGHT, REQUIRED_BITMAP_WIDTH);			Bitmap bp=Utils.getBitmapThumbnail(filePath, minSideLength, REQUIRED_BITMAP_MAXNUMOFPIXELS);		    return bp;			} catch (Exception e) {				e.printStackTrace();			}		}		return null;	}//    private Bitmap getBitmapFromSDCardFile(File file){//        try {//            //decode image size//            BitmapFactory.Options options1 = new BitmapFactory.Options();//            options1.inJustDecodeBounds = true;//            FileInputStream stream1=new FileInputStream(file);//            BitmapFactory.decodeStream(stream1,null,options1);//            stream1.close();//            //            //Find the correct scale value. It should be the power of 2.//            final int REQUIRED_SIZE=70;//            int width_tmp=options1.outWidth, height_tmp=options1.outHeight;//            int scale=1;//            while(true){//                if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)//                    break;//                width_tmp/=2;//                height_tmp/=2;//                scale*=2;//            }//            //            //decode with inSampleSize//            BitmapFactory.Options options2 = new BitmapFactory.Options();//            options2.inSampleSize=scale;//            FileInputStream stream2=new FileInputStream(file);//            Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, options2);//            stream2.close();//            //            System.out.println("xxxxxxxxxxxxxxxxx f.getPath="+file.getPath());//            System.out.println("xxxxxxxxxxxxxxxxx options1.outWidth="+options1.outWidth);//            System.out.println("xxxxxxxxxxxxxxxxx options1.outHeight="+options1.outHeight);//            System.out.println("xxxxxxxxxxxxxxxxx scale="+scale);//            return bitmap;//        } catch (FileNotFoundException e) {//        } //        catch (IOException e) {//            e.printStackTrace();//        }//        return null;//    }  //网络下载图片且保存到SDCard    private Bitmap getBitmapFromNetWork(String url,File file){        try {            Bitmap bitmap=null;            URL imageUrl = new URL(url);            HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();            conn.setConnectTimeout(30000);            conn.setReadTimeout(30000);            conn.setInstanceFollowRedirects(true);            InputStream is=conn.getInputStream();                        //保存其大小            MemoryCache.bitmapsSizeHashMap.put(url,conn.getContentLength());            OutputStream os = new FileOutputStream(file);            Utils.copyStream(is, os);            os.close();            bitmap = getBitmapFromSDCardFile(file);            return bitmap;        } catch (Throwable ex){           ex.printStackTrace();           if(ex instanceof OutOfMemoryError){        	   memoryCache.clear();           }           return null;        }    }        //在UI线程中显示Bitmap    class BitmapDisplayerRunnableInUIThread implements Runnable{        Bitmap bitmap;        WillLoadedImageBean willLoadedImageBean;        public BitmapDisplayerRunnableInUIThread(Bitmap bitmap, WillLoadedImageBean willLoadedImageBean){        	this.bitmap=bitmap;        	this.willLoadedImageBean=willLoadedImageBean;        	}        public void run(){            if(isImageViewReused(willLoadedImageBean)){            	 return;            }            if(bitmap!=null){            	 willLoadedImageBean.imageView.setImageBitmap(bitmap);            }                      else{            	 willLoadedImageBean.imageView.setImageResource(defaultImageId);            }                       }    }    //Task for the queue    private class WillLoadedImageBean    {        public String url;        public ImageView imageView;        public WillLoadedImageBean(String url, ImageView imageView){            this.url=url;             this.imageView=imageView;        }    }        boolean isImageViewReused(WillLoadedImageBean willLoadedImageBean){        String imageUrl=imageViewsWeakHashMap.get(willLoadedImageBean.imageView);        if(imageUrl==null || !imageUrl.equals(willLoadedImageBean.url)){        	  return true;        }                return false;    }        public void clearCache() {        memoryCache.clear();        fileCache.clear();    }}


 

  相关解决方案