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

 

时间: 2024-10-31 01:57:56

Android异步加载图片详解之方式一(2)的相关文章

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

FileCache.java如下: package com.cn.loadImages; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import android.content.Conte

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

MainActivity.java如下: package cn.ideallistview; import java.util.ArrayList; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.

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

Utils.java如下: package cn.loadImages; import java.io.InputStream; import java.io.OutputStream; import android.graphics.Bitmap; import android.graphics.BitmapFactory; public class Utils { public static void copyStream(InputStream is, OutputStream os){

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

main.xml如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" androi

Android异步加载图片详解之方式二(3)

main.xml如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" >

Android LayoutInflater加载布局详解及实例代码

Android  LayoutInflater加载布局详解 对于有一定Android开发经验的同学来说,一定使用过LayoutInflater.inflater()来加载布局文件,但并不一定去深究过它的原理,比如 1.LayoutInflater为什么可以加载layout文件? 2.加载layout文件之后,又是怎么变成供我们使用的View的? 3.我们定义View的时候,如果需要在布局中使用,则必须实现带AttributeSet参数的构造方法,这又是为什么呢? 既然在这篇文章提出来,那说明这三

Android 异步加载图片,使用LruCache和SD卡或手机缓存,效果非常的流畅

异步加载图片的例子,网上也比较多,大部分用了HashMap<String, SoftReference<Drawable>> imageCache ,但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠.另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应

我的Android进阶之旅------&amp;gt;android异步加载图片显示,并且对图片进行缓存实例

先来看看效果示意图: step1:新建项目DataAsyncLoad,如下图所示 step2:设置应用的UI界面 a.应用的主界面    main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="

实例演示Android异步加载图片(转)

本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个ImageView. 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout 3 xmlns:android="http://schemas.android.com/apk/res/a