Android非同步載入圖片詳解之方式一(2)

來源:互聯網
上載者:User

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個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.