Android非同期ロード画像詳細の方法一(2)

18920 ワード

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();
    }
}