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

简介: FileCache.java如下: package cn.loadImages; import java.io.File; import android.

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


 

相关文章
|
5月前
|
XML Java Android开发
Android Studio App开发之对图片进行简单加工(包括放缩,旋转等等 附源码)
Android Studio App开发之对图片进行简单加工(包括放缩,旋转等等 附源码)
50 0
|
5月前
|
XML Java Android开发
Android Studio App开发之使用相机拍摄照片和从相册中选取图片(附源码 超详细必看)
Android Studio App开发之使用相机拍摄照片和从相册中选取图片(附源码 超详细必看)
219 0
|
8月前
|
存储 编解码 Android开发
Android关于图片方向问题
Android关于图片方向问题
41 0
|
1天前
|
Android开发
Android通过手势(多点)缩放和拖拽图片
Android通过手势(多点)缩放和拖拽图片
|
4天前
|
Android开发
Android中Glide加载Https图片失败的解决方案
Android中Glide加载Https图片失败的解决方案
13 1
|
5月前
|
XML JSON Java
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
86 0
|
1月前
|
Android开发
Android保存图片到相册(适配android 10以下及以上)
Android保存图片到相册(适配android 10以下及以上)
29 1
|
7月前
|
SQL 人工智能 移动开发
Android etc1tool之png图片转换pkm 和 zipalign简介
etc1tool 是一种命令行实用程序,可用于将 PNG 图片编码为 ETC1 压缩标准格式(PKM),并将 ETC1 压缩图片解码回 PNG。
|
9月前
|
Java Android开发
Android 保存资源图片到相册最新写法适用于Android10.0及以上
Android 保存资源图片到相册最新写法适用于Android10.0及以上
615 0
|
5月前
|
API Android开发
[Android]图片加载库Glide
[Android]图片加载库Glide
57 0